Merge branch 'project-pineapples' into T1159-MG-Add-memgraph-functions
This commit is contained in:
commit
01d5953bb6
@ -182,7 +182,8 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|||||||
# c99-designator is disabled because of required mixture of designated and
|
# c99-designator is disabled because of required mixture of designated and
|
||||||
# non-designated initializers in Python Query Module code (`py_module.cpp`).
|
# non-designated initializers in Python Query Module code (`py_module.cpp`).
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall \
|
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 \
|
-Werror=return-stack-address \
|
||||||
-Wno-c99-designator \
|
-Wno-c99-designator \
|
||||||
-DBOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT")
|
-DBOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT")
|
||||||
|
68
src/common/errors.hpp
Normal file
68
src/common/errors.hpp
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
// 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 <cstdint>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
namespace memgraph::common {
|
||||||
|
|
||||||
|
enum class ErrorCode : uint8_t {
|
||||||
|
SERIALIZATION_ERROR,
|
||||||
|
NONEXISTENT_OBJECT,
|
||||||
|
DELETED_OBJECT,
|
||||||
|
VERTEX_HAS_EDGES,
|
||||||
|
PROPERTIES_DISABLED,
|
||||||
|
VERTEX_ALREADY_INSERTED,
|
||||||
|
// Schema Violations
|
||||||
|
SCHEMA_NO_SCHEMA_DEFINED_FOR_LABEL,
|
||||||
|
SCHEMA_VERTEX_PROPERTY_WRONG_TYPE,
|
||||||
|
SCHEMA_VERTEX_UPDATE_PRIMARY_KEY,
|
||||||
|
SCHEMA_VERTEX_UPDATE_PRIMARY_LABEL,
|
||||||
|
SCHEMA_VERTEX_SECONDARY_LABEL_IS_PRIMARY,
|
||||||
|
SCHEMA_VERTEX_PRIMARY_PROPERTIES_UNDEFINED,
|
||||||
|
|
||||||
|
OBJECT_NOT_FOUND,
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr std::string_view ErrorCodeToString(const ErrorCode code) {
|
||||||
|
switch (code) {
|
||||||
|
case ErrorCode::SERIALIZATION_ERROR:
|
||||||
|
return "SERIALIZATION_ERROR";
|
||||||
|
case ErrorCode::NONEXISTENT_OBJECT:
|
||||||
|
return "NONEXISTENT_OBJECT";
|
||||||
|
case ErrorCode::DELETED_OBJECT:
|
||||||
|
return "DELETED_OBJECT";
|
||||||
|
case ErrorCode::VERTEX_HAS_EDGES:
|
||||||
|
return "VERTEX_HAS_EDGES";
|
||||||
|
case ErrorCode::PROPERTIES_DISABLED:
|
||||||
|
return "PROPERTIES_DISABLED";
|
||||||
|
case ErrorCode::VERTEX_ALREADY_INSERTED:
|
||||||
|
return "VERTEX_ALREADY_INSERTED";
|
||||||
|
case ErrorCode::SCHEMA_NO_SCHEMA_DEFINED_FOR_LABEL:
|
||||||
|
return "SCHEMA_NO_SCHEMA_DEFINED_FOR_LABEL";
|
||||||
|
case ErrorCode::SCHEMA_VERTEX_PROPERTY_WRONG_TYPE:
|
||||||
|
return "SCHEMA_VERTEX_PROPERTY_WRONG_TYPE";
|
||||||
|
case ErrorCode::SCHEMA_VERTEX_UPDATE_PRIMARY_KEY:
|
||||||
|
return "SCHEMA_VERTEX_UPDATE_PRIMARY_KEY";
|
||||||
|
case ErrorCode::SCHEMA_VERTEX_UPDATE_PRIMARY_LABEL:
|
||||||
|
return "SCHEMA_VERTEX_UPDATE_PRIMARY_LABEL";
|
||||||
|
case ErrorCode::SCHEMA_VERTEX_SECONDARY_LABEL_IS_PRIMARY:
|
||||||
|
return "SCHEMA_VERTEX_SECONDARY_LABEL_IS_PRIMARY";
|
||||||
|
case ErrorCode::SCHEMA_VERTEX_PRIMARY_PROPERTIES_UNDEFINED:
|
||||||
|
return "SCHEMA_VERTEX_PRIMARY_PROPERTIES_UNDEFINED";
|
||||||
|
case ErrorCode::OBJECT_NOT_FOUND:
|
||||||
|
return "OBJECT_NOT_FOUND";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace memgraph::common
|
@ -74,7 +74,7 @@ State RunHandlerV4(Signature signature, TSession &session, State state, Marker m
|
|||||||
}
|
}
|
||||||
case Signature::Route: {
|
case Signature::Route: {
|
||||||
if constexpr (bolt_minor >= 3) {
|
if constexpr (bolt_minor >= 3) {
|
||||||
if (signature == Signature::Route) return HandleRoute<TSession>(session);
|
return HandleRoute<TSession>(session);
|
||||||
} else {
|
} else {
|
||||||
spdlog::trace("Supported only in bolt v4.3");
|
spdlog::trace("Supported only in bolt v4.3");
|
||||||
return State::Close;
|
return State::Close;
|
||||||
|
@ -101,6 +101,28 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
|
|||||||
#undef BINARY_OPERATOR_VISITOR
|
#undef BINARY_OPERATOR_VISITOR
|
||||||
#undef UNARY_OPERATOR_VISITOR
|
#undef UNARY_OPERATOR_VISITOR
|
||||||
|
|
||||||
|
void HandleObjectAccessError(Error &shard_error, const std::string_view accessed_object) {
|
||||||
|
switch (shard_error) {
|
||||||
|
case Error::DELETED_OBJECT:
|
||||||
|
throw ExpressionRuntimeException("Trying to access {} on a deleted object.", accessed_object);
|
||||||
|
case Error::NONEXISTENT_OBJECT:
|
||||||
|
throw ExpressionRuntimeException("Trying to access {} from a node object doesn't exist.", accessed_object);
|
||||||
|
case Error::SERIALIZATION_ERROR:
|
||||||
|
case Error::VERTEX_HAS_EDGES:
|
||||||
|
case Error::PROPERTIES_DISABLED:
|
||||||
|
case Error::VERTEX_ALREADY_INSERTED:
|
||||||
|
case Error::OBJECT_NOT_FOUND:
|
||||||
|
throw ExpressionRuntimeException("Unexpected error when accessing {}.", accessed_object);
|
||||||
|
case Error::SCHEMA_NO_SCHEMA_DEFINED_FOR_LABEL:
|
||||||
|
case Error::SCHEMA_VERTEX_PROPERTY_WRONG_TYPE:
|
||||||
|
case Error::SCHEMA_VERTEX_UPDATE_PRIMARY_KEY:
|
||||||
|
case Error::SCHEMA_VERTEX_UPDATE_PRIMARY_LABEL:
|
||||||
|
case Error::SCHEMA_VERTEX_SECONDARY_LABEL_IS_PRIMARY:
|
||||||
|
case Error::SCHEMA_VERTEX_PRIMARY_PROPERTIES_UNDEFINED:
|
||||||
|
throw ExpressionRuntimeException("Unexpected schema violation when accessing {}.", accessed_object);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TypedValue Visit(AndOperator &op) override {
|
TypedValue Visit(AndOperator &op) override {
|
||||||
auto value1 = op.expression1_->Accept(*this);
|
auto value1 = op.expression1_->Accept(*this);
|
||||||
if (value1.IsBool() && !value1.ValueBool()) {
|
if (value1.IsBool() && !value1.ValueBool()) {
|
||||||
@ -397,17 +419,7 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
|
|||||||
has_label = vertex.HasLabel(StorageView::NEW, GetLabel(label));
|
has_label = vertex.HasLabel(StorageView::NEW, GetLabel(label));
|
||||||
}
|
}
|
||||||
if (has_label.HasError()) {
|
if (has_label.HasError()) {
|
||||||
switch (has_label.GetError()) {
|
HandleObjectAccessError(has_label.GetError().code, "labels");
|
||||||
case Error::DELETED_OBJECT:
|
|
||||||
throw ExpressionRuntimeException("Trying to access labels on a deleted node.");
|
|
||||||
case Error::NONEXISTENT_OBJECT:
|
|
||||||
throw ExpressionRuntimeException("Trying to access labels from a node that doesn't exist.");
|
|
||||||
case Error::SERIALIZATION_ERROR:
|
|
||||||
case Error::VERTEX_HAS_EDGES:
|
|
||||||
case Error::PROPERTIES_DISABLED:
|
|
||||||
case Error::VERTEX_ALREADY_INSERTED:
|
|
||||||
throw ExpressionRuntimeException("Unexpected error when accessing labels.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return *has_label;
|
return *has_label;
|
||||||
}
|
}
|
||||||
@ -744,17 +756,7 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
|
|||||||
maybe_prop = record_accessor.GetProperty(StorageView::NEW, ctx_->properties[prop.ix]);
|
maybe_prop = record_accessor.GetProperty(StorageView::NEW, ctx_->properties[prop.ix]);
|
||||||
}
|
}
|
||||||
if (maybe_prop.HasError()) {
|
if (maybe_prop.HasError()) {
|
||||||
switch (maybe_prop.GetError()) {
|
HandleObjectAccessError(maybe_prop.GetError().code, "property");
|
||||||
case Error::DELETED_OBJECT:
|
|
||||||
throw ExpressionRuntimeException("Trying to get a property from a deleted object.");
|
|
||||||
case Error::NONEXISTENT_OBJECT:
|
|
||||||
throw ExpressionRuntimeException("Trying to get a property from an object that doesn't exist.");
|
|
||||||
case Error::SERIALIZATION_ERROR:
|
|
||||||
case Error::VERTEX_HAS_EDGES:
|
|
||||||
case Error::PROPERTIES_DISABLED:
|
|
||||||
case Error::VERTEX_ALREADY_INSERTED:
|
|
||||||
throw ExpressionRuntimeException("Unexpected error when getting a property.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return conv_(*maybe_prop, ctx_->memory);
|
return conv_(*maybe_prop, ctx_->memory);
|
||||||
}
|
}
|
||||||
@ -773,17 +775,7 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
|
|||||||
maybe_prop = record_accessor.GetProperty(view_, dba_->NameToProperty(name));
|
maybe_prop = record_accessor.GetProperty(view_, dba_->NameToProperty(name));
|
||||||
}
|
}
|
||||||
if (maybe_prop.HasError()) {
|
if (maybe_prop.HasError()) {
|
||||||
switch (maybe_prop.GetError()) {
|
HandleObjectAccessError(maybe_prop.GetError().code, "property");
|
||||||
case Error::DELETED_OBJECT:
|
|
||||||
throw ExpressionRuntimeException("Trying to get a property from a deleted object.");
|
|
||||||
case Error::NONEXISTENT_OBJECT:
|
|
||||||
throw ExpressionRuntimeException("Trying to get a property from an object that doesn't exist.");
|
|
||||||
case Error::SERIALIZATION_ERROR:
|
|
||||||
case Error::VERTEX_HAS_EDGES:
|
|
||||||
case Error::PROPERTIES_DISABLED:
|
|
||||||
case Error::VERTEX_ALREADY_INSERTED:
|
|
||||||
throw ExpressionRuntimeException("Unexpected error when getting a property.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return conv_(*maybe_prop, ctx_->memory);
|
return conv_(*maybe_prop, ctx_->memory);
|
||||||
}
|
}
|
||||||
|
@ -15,13 +15,13 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "common/errors.hpp"
|
||||||
#include "coordinator/shard_map.hpp"
|
#include "coordinator/shard_map.hpp"
|
||||||
#include "query/v2/accessors.hpp"
|
#include "query/v2/accessors.hpp"
|
||||||
#include "query/v2/requests.hpp"
|
#include "query/v2/requests.hpp"
|
||||||
#include "query/v2/shard_request_manager.hpp"
|
#include "query/v2/shard_request_manager.hpp"
|
||||||
#include "storage/v3/edge_accessor.hpp"
|
#include "storage/v3/edge_accessor.hpp"
|
||||||
#include "storage/v3/id_types.hpp"
|
#include "storage/v3/id_types.hpp"
|
||||||
#include "storage/v3/result.hpp"
|
|
||||||
#include "storage/v3/shard.hpp"
|
#include "storage/v3/shard.hpp"
|
||||||
#include "storage/v3/vertex_accessor.hpp"
|
#include "storage/v3/vertex_accessor.hpp"
|
||||||
#include "storage/v3/view.hpp"
|
#include "storage/v3/view.hpp"
|
||||||
@ -71,8 +71,8 @@ query::v2::TypedValue ToTypedValue(const Value &value) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
storage::v3::Result<communication::bolt::Vertex> ToBoltVertex(
|
communication::bolt::Vertex ToBoltVertex(const query::v2::accessors::VertexAccessor &vertex,
|
||||||
const query::v2::accessors::VertexAccessor &vertex, const msgs::ShardRequestManagerInterface *shard_request_manager,
|
const msgs::ShardRequestManagerInterface *shard_request_manager,
|
||||||
storage::v3::View /*view*/) {
|
storage::v3::View /*view*/) {
|
||||||
auto id = communication::bolt::Id::FromUint(0);
|
auto id = communication::bolt::Id::FromUint(0);
|
||||||
|
|
||||||
@ -91,8 +91,8 @@ storage::v3::Result<communication::bolt::Vertex> ToBoltVertex(
|
|||||||
return communication::bolt::Vertex{id, new_labels, new_properties};
|
return communication::bolt::Vertex{id, new_labels, new_properties};
|
||||||
}
|
}
|
||||||
|
|
||||||
storage::v3::Result<communication::bolt::Edge> ToBoltEdge(
|
communication::bolt::Edge ToBoltEdge(const query::v2::accessors::EdgeAccessor &edge,
|
||||||
const query::v2::accessors::EdgeAccessor &edge, const msgs::ShardRequestManagerInterface *shard_request_manager,
|
const msgs::ShardRequestManagerInterface *shard_request_manager,
|
||||||
storage::v3::View /*view*/) {
|
storage::v3::View /*view*/) {
|
||||||
// TODO(jbajic) Fix bolt communication
|
// TODO(jbajic) Fix bolt communication
|
||||||
auto id = communication::bolt::Id::FromUint(0);
|
auto id = communication::bolt::Id::FromUint(0);
|
||||||
@ -108,69 +108,64 @@ storage::v3::Result<communication::bolt::Edge> ToBoltEdge(
|
|||||||
return communication::bolt::Edge{id, from, to, type, new_properties};
|
return communication::bolt::Edge{id, from, to, type, new_properties};
|
||||||
}
|
}
|
||||||
|
|
||||||
storage::v3::Result<communication::bolt::Path> ToBoltPath(
|
communication::bolt::Path ToBoltPath(const query::v2::accessors::Path & /*edge*/,
|
||||||
const query::v2::accessors::Path & /*edge*/, const msgs::ShardRequestManagerInterface * /*shard_request_manager*/,
|
const msgs::ShardRequestManagerInterface * /*shard_request_manager*/,
|
||||||
storage::v3::View /*view*/) {
|
storage::v3::View /*view*/) {
|
||||||
// TODO(jbajic) Fix bolt communication
|
// TODO(jbajic) Fix bolt communication
|
||||||
return {storage::v3::Error::DELETED_OBJECT};
|
MG_ASSERT(false, "Path is unimplemented!");
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
storage::v3::Result<Value> ToBoltValue(const query::v2::TypedValue &value,
|
Value ToBoltValue(const query::v2::TypedValue &value, const msgs::ShardRequestManagerInterface *shard_request_manager,
|
||||||
const msgs::ShardRequestManagerInterface *shard_request_manager,
|
|
||||||
storage::v3::View view) {
|
storage::v3::View view) {
|
||||||
switch (value.type()) {
|
switch (value.type()) {
|
||||||
case query::v2::TypedValue::Type::Null:
|
case query::v2::TypedValue::Type::Null:
|
||||||
return Value();
|
return {};
|
||||||
case query::v2::TypedValue::Type::Bool:
|
case query::v2::TypedValue::Type::Bool:
|
||||||
return Value(value.ValueBool());
|
return {value.ValueBool()};
|
||||||
case query::v2::TypedValue::Type::Int:
|
case query::v2::TypedValue::Type::Int:
|
||||||
return Value(value.ValueInt());
|
return {value.ValueInt()};
|
||||||
case query::v2::TypedValue::Type::Double:
|
case query::v2::TypedValue::Type::Double:
|
||||||
return Value(value.ValueDouble());
|
return {value.ValueDouble()};
|
||||||
case query::v2::TypedValue::Type::String:
|
case query::v2::TypedValue::Type::String:
|
||||||
return Value(std::string(value.ValueString()));
|
return {std::string(value.ValueString())};
|
||||||
case query::v2::TypedValue::Type::List: {
|
case query::v2::TypedValue::Type::List: {
|
||||||
std::vector<Value> values;
|
std::vector<Value> values;
|
||||||
values.reserve(value.ValueList().size());
|
values.reserve(value.ValueList().size());
|
||||||
for (const auto &v : value.ValueList()) {
|
for (const auto &v : value.ValueList()) {
|
||||||
auto maybe_value = ToBoltValue(v, shard_request_manager, view);
|
auto value = ToBoltValue(v, shard_request_manager, view);
|
||||||
if (maybe_value.HasError()) return maybe_value.GetError();
|
values.emplace_back(std::move(value));
|
||||||
values.emplace_back(std::move(*maybe_value));
|
|
||||||
}
|
}
|
||||||
return Value(std::move(values));
|
return {std::move(values)};
|
||||||
}
|
}
|
||||||
case query::v2::TypedValue::Type::Map: {
|
case query::v2::TypedValue::Type::Map: {
|
||||||
std::map<std::string, Value> map;
|
std::map<std::string, Value> map;
|
||||||
for (const auto &kv : value.ValueMap()) {
|
for (const auto &kv : value.ValueMap()) {
|
||||||
auto maybe_value = ToBoltValue(kv.second, shard_request_manager, view);
|
auto value = ToBoltValue(kv.second, shard_request_manager, view);
|
||||||
if (maybe_value.HasError()) return maybe_value.GetError();
|
map.emplace(kv.first, std::move(value));
|
||||||
map.emplace(kv.first, std::move(*maybe_value));
|
|
||||||
}
|
}
|
||||||
return Value(std::move(map));
|
return {std::move(map)};
|
||||||
}
|
}
|
||||||
case query::v2::TypedValue::Type::Vertex: {
|
case query::v2::TypedValue::Type::Vertex: {
|
||||||
auto maybe_vertex = ToBoltVertex(value.ValueVertex(), shard_request_manager, view);
|
auto vertex = ToBoltVertex(value.ValueVertex(), shard_request_manager, view);
|
||||||
if (maybe_vertex.HasError()) return maybe_vertex.GetError();
|
return {std::move(vertex)};
|
||||||
return Value(std::move(*maybe_vertex));
|
|
||||||
}
|
}
|
||||||
case query::v2::TypedValue::Type::Edge: {
|
case query::v2::TypedValue::Type::Edge: {
|
||||||
auto maybe_edge = ToBoltEdge(value.ValueEdge(), shard_request_manager, view);
|
auto edge = ToBoltEdge(value.ValueEdge(), shard_request_manager, view);
|
||||||
if (maybe_edge.HasError()) return maybe_edge.GetError();
|
return {std::move(edge)};
|
||||||
return Value(std::move(*maybe_edge));
|
|
||||||
}
|
}
|
||||||
case query::v2::TypedValue::Type::Path: {
|
case query::v2::TypedValue::Type::Path: {
|
||||||
auto maybe_path = ToBoltPath(value.ValuePath(), shard_request_manager, view);
|
auto path = ToBoltPath(value.ValuePath(), shard_request_manager, view);
|
||||||
if (maybe_path.HasError()) return maybe_path.GetError();
|
return {std::move(path)};
|
||||||
return Value(std::move(*maybe_path));
|
|
||||||
}
|
}
|
||||||
case query::v2::TypedValue::Type::Date:
|
case query::v2::TypedValue::Type::Date:
|
||||||
return Value(value.ValueDate());
|
return {value.ValueDate()};
|
||||||
case query::v2::TypedValue::Type::LocalTime:
|
case query::v2::TypedValue::Type::LocalTime:
|
||||||
return Value(value.ValueLocalTime());
|
return {value.ValueLocalTime()};
|
||||||
case query::v2::TypedValue::Type::LocalDateTime:
|
case query::v2::TypedValue::Type::LocalDateTime:
|
||||||
return Value(value.ValueLocalDateTime());
|
return {value.ValueLocalDateTime()};
|
||||||
case query::v2::TypedValue::Type::Duration:
|
case query::v2::TypedValue::Type::Duration:
|
||||||
return Value(value.ValueDuration());
|
return {value.ValueDuration()};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include "storage/v3/result.hpp"
|
#include "storage/v3/result.hpp"
|
||||||
#include "storage/v3/shard.hpp"
|
#include "storage/v3/shard.hpp"
|
||||||
#include "storage/v3/view.hpp"
|
#include "storage/v3/view.hpp"
|
||||||
|
#include "utils/result.hpp"
|
||||||
|
|
||||||
namespace memgraph::storage::v3 {
|
namespace memgraph::storage::v3 {
|
||||||
class EdgeAccessor;
|
class EdgeAccessor;
|
||||||
@ -35,8 +36,8 @@ namespace memgraph::glue::v2 {
|
|||||||
/// @param storage::v3::View for deciding which vertex attributes are visible.
|
/// @param storage::v3::View for deciding which vertex attributes are visible.
|
||||||
///
|
///
|
||||||
/// @throw std::bad_alloc
|
/// @throw std::bad_alloc
|
||||||
storage::v3::Result<communication::bolt::Vertex> ToBoltVertex(
|
communication::bolt::Vertex ToBoltVertex(const storage::v3::VertexAccessor &vertex,
|
||||||
const storage::v3::VertexAccessor &vertex, const msgs::ShardRequestManagerInterface *shard_request_manager,
|
const msgs::ShardRequestManagerInterface *shard_request_manager,
|
||||||
storage::v3::View view);
|
storage::v3::View view);
|
||||||
|
|
||||||
/// @param storage::v3::EdgeAccessor for converting to communication::bolt::Edge.
|
/// @param storage::v3::EdgeAccessor for converting to communication::bolt::Edge.
|
||||||
@ -44,8 +45,8 @@ storage::v3::Result<communication::bolt::Vertex> ToBoltVertex(
|
|||||||
/// @param storage::v3::View for deciding which edge attributes are visible.
|
/// @param storage::v3::View for deciding which edge attributes are visible.
|
||||||
///
|
///
|
||||||
/// @throw std::bad_alloc
|
/// @throw std::bad_alloc
|
||||||
storage::v3::Result<communication::bolt::Edge> ToBoltEdge(
|
communication::bolt::Edge ToBoltEdge(const storage::v3::EdgeAccessor &edge,
|
||||||
const storage::v3::EdgeAccessor &edge, const msgs::ShardRequestManagerInterface *shard_request_manager,
|
const msgs::ShardRequestManagerInterface *shard_request_manager,
|
||||||
storage::v3::View view);
|
storage::v3::View view);
|
||||||
|
|
||||||
/// @param query::v2::Path for converting to communication::bolt::Path.
|
/// @param query::v2::Path for converting to communication::bolt::Path.
|
||||||
@ -53,8 +54,8 @@ storage::v3::Result<communication::bolt::Edge> ToBoltEdge(
|
|||||||
/// @param storage::v3::View for ToBoltVertex and ToBoltEdge.
|
/// @param storage::v3::View for ToBoltVertex and ToBoltEdge.
|
||||||
///
|
///
|
||||||
/// @throw std::bad_alloc
|
/// @throw std::bad_alloc
|
||||||
storage::v3::Result<communication::bolt::Path> ToBoltPath(
|
communication::bolt::Path ToBoltPath(const query::v2::accessors::Path &path,
|
||||||
const query::v2::accessors::Path &path, const msgs::ShardRequestManagerInterface *shard_request_manager,
|
const msgs::ShardRequestManagerInterface *shard_request_manager,
|
||||||
storage::v3::View view);
|
storage::v3::View view);
|
||||||
|
|
||||||
/// @param query::v2::TypedValue for converting to communication::bolt::Value.
|
/// @param query::v2::TypedValue for converting to communication::bolt::Value.
|
||||||
@ -62,8 +63,8 @@ storage::v3::Result<communication::bolt::Path> ToBoltPath(
|
|||||||
/// @param storage::v3::View for ToBoltVertex and ToBoltEdge.
|
/// @param storage::v3::View for ToBoltVertex and ToBoltEdge.
|
||||||
///
|
///
|
||||||
/// @throw std::bad_alloc
|
/// @throw std::bad_alloc
|
||||||
storage::v3::Result<communication::bolt::Value> ToBoltValue(
|
communication::bolt::Value ToBoltValue(const query::v2::TypedValue &value,
|
||||||
const query::v2::TypedValue &value, const msgs::ShardRequestManagerInterface *shard_request_manager,
|
const msgs::ShardRequestManagerInterface *shard_request_manager,
|
||||||
storage::v3::View view);
|
storage::v3::View view);
|
||||||
|
|
||||||
query::v2::TypedValue ToTypedValue(const communication::bolt::Value &value);
|
query::v2::TypedValue ToTypedValue(const communication::bolt::Value &value);
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
#include <spdlog/sinks/dist_sink.h>
|
#include <spdlog/sinks/dist_sink.h>
|
||||||
#include <spdlog/sinks/stdout_color_sinks.h>
|
#include <spdlog/sinks/stdout_color_sinks.h>
|
||||||
|
|
||||||
|
#include "common/errors.hpp"
|
||||||
#include "communication/bolt/v1/constants.hpp"
|
#include "communication/bolt/v1/constants.hpp"
|
||||||
#include "communication/websocket/auth.hpp"
|
#include "communication/websocket/auth.hpp"
|
||||||
#include "communication/websocket/server.hpp"
|
#include "communication/websocket/server.hpp"
|
||||||
@ -480,20 +481,9 @@ class BoltSession final : public memgraph::communication::bolt::Session<memgraph
|
|||||||
const auto &summary = interpreter_.Pull(&stream, n, qid);
|
const auto &summary = interpreter_.Pull(&stream, n, qid);
|
||||||
std::map<std::string, memgraph::communication::bolt::Value> decoded_summary;
|
std::map<std::string, memgraph::communication::bolt::Value> decoded_summary;
|
||||||
for (const auto &kv : summary) {
|
for (const auto &kv : summary) {
|
||||||
auto maybe_value = memgraph::glue::v2::ToBoltValue(kv.second, interpreter_.GetShardRequestManager(),
|
auto bolt_value = memgraph::glue::v2::ToBoltValue(kv.second, interpreter_.GetShardRequestManager(),
|
||||||
memgraph::storage::v3::View::NEW);
|
memgraph::storage::v3::View::NEW);
|
||||||
if (maybe_value.HasError()) {
|
decoded_summary.emplace(kv.first, std::move(bolt_value));
|
||||||
switch (maybe_value.GetError()) {
|
|
||||||
case memgraph::storage::v3::Error::DELETED_OBJECT:
|
|
||||||
case memgraph::storage::v3::Error::SERIALIZATION_ERROR:
|
|
||||||
case memgraph::storage::v3::Error::VERTEX_HAS_EDGES:
|
|
||||||
case memgraph::storage::v3::Error::PROPERTIES_DISABLED:
|
|
||||||
case memgraph::storage::v3::Error::NONEXISTENT_OBJECT:
|
|
||||||
case memgraph::storage::v3::Error::VERTEX_ALREADY_INSERTED:
|
|
||||||
throw memgraph::communication::bolt::ClientError("Unexpected storage error when streaming summary.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
decoded_summary.emplace(kv.first, std::move(*maybe_value));
|
|
||||||
}
|
}
|
||||||
return decoded_summary;
|
return decoded_summary;
|
||||||
} catch (const memgraph::query::v2::QueryException &e) {
|
} catch (const memgraph::query::v2::QueryException &e) {
|
||||||
@ -514,21 +504,8 @@ class BoltSession final : public memgraph::communication::bolt::Session<memgraph
|
|||||||
std::vector<memgraph::communication::bolt::Value> decoded_values;
|
std::vector<memgraph::communication::bolt::Value> decoded_values;
|
||||||
decoded_values.reserve(values.size());
|
decoded_values.reserve(values.size());
|
||||||
for (const auto &v : values) {
|
for (const auto &v : values) {
|
||||||
auto maybe_value = memgraph::glue::v2::ToBoltValue(v, shard_request_manager_, memgraph::storage::v3::View::NEW);
|
auto bolt_value = memgraph::glue::v2::ToBoltValue(v, shard_request_manager_, memgraph::storage::v3::View::NEW);
|
||||||
if (maybe_value.HasError()) {
|
decoded_values.emplace_back(std::move(bolt_value));
|
||||||
switch (maybe_value.GetError()) {
|
|
||||||
case memgraph::storage::v3::Error::DELETED_OBJECT:
|
|
||||||
throw memgraph::communication::bolt::ClientError("Returning a deleted object as a result.");
|
|
||||||
case memgraph::storage::v3::Error::NONEXISTENT_OBJECT:
|
|
||||||
throw memgraph::communication::bolt::ClientError("Returning a nonexistent object as a result.");
|
|
||||||
case memgraph::storage::v3::Error::VERTEX_HAS_EDGES:
|
|
||||||
case memgraph::storage::v3::Error::SERIALIZATION_ERROR:
|
|
||||||
case memgraph::storage::v3::Error::PROPERTIES_DISABLED:
|
|
||||||
case memgraph::storage::v3::Error::VERTEX_ALREADY_INSERTED:
|
|
||||||
throw memgraph::communication::bolt::ClientError("Unexpected storage error when streaming results.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
decoded_values.emplace_back(std::move(*maybe_value));
|
|
||||||
}
|
}
|
||||||
encoder_->MessageRecord(decoded_values);
|
encoder_->MessageRecord(decoded_values);
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include "query/v2/requests.hpp"
|
#include "query/v2/requests.hpp"
|
||||||
#include "storage/v3/conversions.hpp"
|
#include "storage/v3/conversions.hpp"
|
||||||
#include "storage/v3/property_value.hpp"
|
#include "storage/v3/property_value.hpp"
|
||||||
|
#include "storage/v3/result.hpp"
|
||||||
#include "storage/v3/view.hpp"
|
#include "storage/v3/view.hpp"
|
||||||
|
|
||||||
namespace memgraph::msgs {
|
namespace memgraph::msgs {
|
||||||
@ -43,6 +44,6 @@ class Callable {
|
|||||||
} // namespace detail
|
} // namespace detail
|
||||||
using ExpressionEvaluator = memgraph::expr::ExpressionEvaluator<
|
using ExpressionEvaluator = memgraph::expr::ExpressionEvaluator<
|
||||||
TypedValue, memgraph::query::v2::EvaluationContext, memgraph::msgs::ShardRequestManagerInterface, storage::v3::View,
|
TypedValue, memgraph::query::v2::EvaluationContext, memgraph::msgs::ShardRequestManagerInterface, storage::v3::View,
|
||||||
storage::v3::LabelId, msgs::Value, detail::Callable, memgraph::storage::v3::Error, memgraph::expr::QueryEngineTag>;
|
storage::v3::LabelId, msgs::Value, detail::Callable, common::ErrorCode, memgraph::expr::QueryEngineTag>;
|
||||||
|
|
||||||
} // namespace memgraph::query::v2
|
} // namespace memgraph::query::v2
|
||||||
|
@ -20,7 +20,6 @@
|
|||||||
|
|
||||||
#include "query/v2/bindings/symbol.hpp"
|
#include "query/v2/bindings/symbol.hpp"
|
||||||
#include "query/v2/bindings/typed_value.hpp"
|
#include "query/v2/bindings/typed_value.hpp"
|
||||||
#include "query/v2/db_accessor.hpp"
|
|
||||||
#include "query/v2/exceptions.hpp"
|
#include "query/v2/exceptions.hpp"
|
||||||
#include "query/v2/frontend/ast/ast.hpp"
|
#include "query/v2/frontend/ast/ast.hpp"
|
||||||
#include "query/v2/path.hpp"
|
#include "query/v2/path.hpp"
|
||||||
@ -28,7 +27,6 @@
|
|||||||
#include "storage/v3/id_types.hpp"
|
#include "storage/v3/id_types.hpp"
|
||||||
#include "storage/v3/property_value.hpp"
|
#include "storage/v3/property_value.hpp"
|
||||||
#include "storage/v3/result.hpp"
|
#include "storage/v3/result.hpp"
|
||||||
#include "storage/v3/shard_operation_result.hpp"
|
|
||||||
#include "storage/v3/view.hpp"
|
#include "storage/v3/view.hpp"
|
||||||
#include "utils/exceptions.hpp"
|
#include "utils/exceptions.hpp"
|
||||||
#include "utils/logging.hpp"
|
#include "utils/logging.hpp"
|
||||||
@ -82,39 +80,5 @@ inline void ExpectType(const Symbol &symbol, const TypedValue &value, TypedValue
|
|||||||
throw QueryRuntimeException("Expected a {} for '{}', but got {}.", expected, symbol.name(), value.type());
|
throw QueryRuntimeException("Expected a {} for '{}', but got {}.", expected, symbol.name(), value.type());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
concept AccessorWithSetProperty = requires(T accessor, const storage::v3::PropertyId key,
|
|
||||||
const storage::v3::PropertyValue new_value) {
|
|
||||||
{ accessor.SetProperty(key, new_value) } -> std::same_as<storage::v3::Result<storage::v3::PropertyValue>>;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
concept AccessorWithSetPropertyAndValidate = requires(T accessor, const storage::v3::PropertyId key,
|
|
||||||
const storage::v3::PropertyValue new_value) {
|
|
||||||
{
|
|
||||||
accessor.SetPropertyAndValidate(key, new_value)
|
|
||||||
} -> std::same_as<storage::v3::ShardOperationResult<storage::v3::PropertyValue>>;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename TRecordAccessor>
|
|
||||||
concept RecordAccessor =
|
|
||||||
AccessorWithSetProperty<TRecordAccessor> || AccessorWithSetPropertyAndValidate<TRecordAccessor>;
|
|
||||||
|
|
||||||
inline void HandleErrorOnPropertyUpdate(const storage::v3::Error error) {
|
|
||||||
switch (error) {
|
|
||||||
case storage::v3::Error::SERIALIZATION_ERROR:
|
|
||||||
throw TransactionSerializationException();
|
|
||||||
case storage::v3::Error::DELETED_OBJECT:
|
|
||||||
throw QueryRuntimeException("Trying to set properties on a deleted object.");
|
|
||||||
case storage::v3::Error::PROPERTIES_DISABLED:
|
|
||||||
throw QueryRuntimeException("Can't set property because properties on edges are disabled.");
|
|
||||||
case storage::v3::Error::VERTEX_HAS_EDGES:
|
|
||||||
case storage::v3::Error::NONEXISTENT_OBJECT:
|
|
||||||
case storage::v3::Error::VERTEX_ALREADY_INSERTED:
|
|
||||||
|
|
||||||
throw QueryRuntimeException("Unexpected error when setting a property.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t QueryTimestamp();
|
int64_t QueryTimestamp();
|
||||||
} // namespace memgraph::query::v2
|
} // namespace memgraph::query::v2
|
||||||
|
@ -23,7 +23,6 @@
|
|||||||
#include "storage/v3/key_store.hpp"
|
#include "storage/v3/key_store.hpp"
|
||||||
#include "storage/v3/property_value.hpp"
|
#include "storage/v3/property_value.hpp"
|
||||||
#include "storage/v3/result.hpp"
|
#include "storage/v3/result.hpp"
|
||||||
#include "storage/v3/shard_operation_result.hpp"
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////
|
||||||
// Our communication layer and query engine don't mix
|
// Our communication layer and query engine don't mix
|
||||||
@ -65,24 +64,11 @@ class EdgeAccessor final {
|
|||||||
|
|
||||||
auto Properties(storage::v3::View view) const { return impl_.Properties(view); }
|
auto Properties(storage::v3::View view) const { return impl_.Properties(view); }
|
||||||
|
|
||||||
storage::v3::Result<storage::v3::PropertyValue> GetProperty(storage::v3::View view,
|
storage::v3::ShardResult<storage::v3::PropertyValue> GetProperty(storage::v3::View view,
|
||||||
storage::v3::PropertyId key) const {
|
storage::v3::PropertyId key) const {
|
||||||
return impl_.GetProperty(key, view);
|
return impl_.GetProperty(key, view);
|
||||||
}
|
}
|
||||||
|
|
||||||
storage::v3::Result<storage::v3::PropertyValue> SetProperty(storage::v3::PropertyId key,
|
|
||||||
const storage::v3::PropertyValue &value) {
|
|
||||||
return impl_.SetProperty(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
storage::v3::Result<storage::v3::PropertyValue> RemoveProperty(storage::v3::PropertyId key) {
|
|
||||||
return SetProperty(key, storage::v3::PropertyValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
storage::v3::Result<std::map<storage::v3::PropertyId, storage::v3::PropertyValue>> ClearProperties() {
|
|
||||||
return impl_.ClearProperties();
|
|
||||||
}
|
|
||||||
|
|
||||||
VertexAccessor To() const;
|
VertexAccessor To() const;
|
||||||
|
|
||||||
VertexAccessor From() const;
|
VertexAccessor From() const;
|
||||||
@ -114,53 +100,19 @@ class VertexAccessor final {
|
|||||||
|
|
||||||
auto PrimaryKey(storage::v3::View view) const { return impl_.PrimaryKey(view); }
|
auto PrimaryKey(storage::v3::View view) const { return impl_.PrimaryKey(view); }
|
||||||
|
|
||||||
storage::v3::ShardOperationResult<bool> AddLabel(storage::v3::LabelId label) {
|
storage::v3::ShardResult<bool> HasLabel(storage::v3::View view, storage::v3::LabelId label) const {
|
||||||
return impl_.AddLabelAndValidate(label);
|
|
||||||
}
|
|
||||||
|
|
||||||
storage::v3::ShardOperationResult<bool> AddLabelAndValidate(storage::v3::LabelId label) {
|
|
||||||
return impl_.AddLabelAndValidate(label);
|
|
||||||
}
|
|
||||||
|
|
||||||
storage::v3::ShardOperationResult<bool> RemoveLabel(storage::v3::LabelId label) {
|
|
||||||
return impl_.RemoveLabelAndValidate(label);
|
|
||||||
}
|
|
||||||
|
|
||||||
storage::v3::ShardOperationResult<bool> RemoveLabelAndValidate(storage::v3::LabelId label) {
|
|
||||||
return impl_.RemoveLabelAndValidate(label);
|
|
||||||
}
|
|
||||||
|
|
||||||
storage::v3::Result<bool> HasLabel(storage::v3::View view, storage::v3::LabelId label) const {
|
|
||||||
return impl_.HasLabel(label, view);
|
return impl_.HasLabel(label, view);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Properties(storage::v3::View view) const { return impl_.Properties(view); }
|
auto Properties(storage::v3::View view) const { return impl_.Properties(view); }
|
||||||
|
|
||||||
storage::v3::Result<storage::v3::PropertyValue> GetProperty(storage::v3::View view,
|
storage::v3::ShardResult<storage::v3::PropertyValue> GetProperty(storage::v3::View view,
|
||||||
storage::v3::PropertyId key) const {
|
storage::v3::PropertyId key) const {
|
||||||
return impl_.GetProperty(key, view);
|
return impl_.GetProperty(key, view);
|
||||||
}
|
}
|
||||||
|
|
||||||
storage::v3::ShardOperationResult<storage::v3::PropertyValue> SetProperty(storage::v3::PropertyId key,
|
|
||||||
const storage::v3::PropertyValue &value) {
|
|
||||||
return impl_.SetPropertyAndValidate(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
storage::v3::ShardOperationResult<storage::v3::PropertyValue> SetPropertyAndValidate(
|
|
||||||
storage::v3::PropertyId key, const storage::v3::PropertyValue &value) {
|
|
||||||
return impl_.SetPropertyAndValidate(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
storage::v3::ShardOperationResult<storage::v3::PropertyValue> RemovePropertyAndValidate(storage::v3::PropertyId key) {
|
|
||||||
return SetPropertyAndValidate(key, storage::v3::PropertyValue{});
|
|
||||||
}
|
|
||||||
|
|
||||||
storage::v3::Result<std::map<storage::v3::PropertyId, storage::v3::PropertyValue>> ClearProperties() {
|
|
||||||
return impl_.ClearProperties();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto InEdges(storage::v3::View view, const std::vector<storage::v3::EdgeTypeId> &edge_types) const
|
auto InEdges(storage::v3::View view, const std::vector<storage::v3::EdgeTypeId> &edge_types) const
|
||||||
-> storage::v3::Result<decltype(iter::imap(MakeEdgeAccessor, *impl_.InEdges(view)))> {
|
-> storage::v3::ShardResult<decltype(iter::imap(MakeEdgeAccessor, *impl_.InEdges(view)))> {
|
||||||
auto maybe_edges = impl_.InEdges(view, edge_types);
|
auto maybe_edges = impl_.InEdges(view, edge_types);
|
||||||
if (maybe_edges.HasError()) return maybe_edges.GetError();
|
if (maybe_edges.HasError()) return maybe_edges.GetError();
|
||||||
return iter::imap(MakeEdgeAccessor, std::move(*maybe_edges));
|
return iter::imap(MakeEdgeAccessor, std::move(*maybe_edges));
|
||||||
@ -170,7 +122,7 @@ class VertexAccessor final {
|
|||||||
|
|
||||||
auto InEdges(storage::v3::View view, const std::vector<storage::v3::EdgeTypeId> &edge_types,
|
auto InEdges(storage::v3::View view, const std::vector<storage::v3::EdgeTypeId> &edge_types,
|
||||||
const VertexAccessor &dest) const
|
const VertexAccessor &dest) const
|
||||||
-> storage::v3::Result<decltype(iter::imap(MakeEdgeAccessor, *impl_.InEdges(view)))> {
|
-> storage::v3::ShardResult<decltype(iter::imap(MakeEdgeAccessor, *impl_.InEdges(view)))> {
|
||||||
const auto dest_id = dest.impl_.Id(view).GetValue();
|
const auto dest_id = dest.impl_.Id(view).GetValue();
|
||||||
auto maybe_edges = impl_.InEdges(view, edge_types, &dest_id);
|
auto maybe_edges = impl_.InEdges(view, edge_types, &dest_id);
|
||||||
if (maybe_edges.HasError()) return maybe_edges.GetError();
|
if (maybe_edges.HasError()) return maybe_edges.GetError();
|
||||||
@ -178,7 +130,7 @@ class VertexAccessor final {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto OutEdges(storage::v3::View view, const std::vector<storage::v3::EdgeTypeId> &edge_types) const
|
auto OutEdges(storage::v3::View view, const std::vector<storage::v3::EdgeTypeId> &edge_types) const
|
||||||
-> storage::v3::Result<decltype(iter::imap(MakeEdgeAccessor, *impl_.OutEdges(view)))> {
|
-> storage::v3::ShardResult<decltype(iter::imap(MakeEdgeAccessor, *impl_.OutEdges(view)))> {
|
||||||
auto maybe_edges = impl_.OutEdges(view, edge_types);
|
auto maybe_edges = impl_.OutEdges(view, edge_types);
|
||||||
if (maybe_edges.HasError()) return maybe_edges.GetError();
|
if (maybe_edges.HasError()) return maybe_edges.GetError();
|
||||||
return iter::imap(MakeEdgeAccessor, std::move(*maybe_edges));
|
return iter::imap(MakeEdgeAccessor, std::move(*maybe_edges));
|
||||||
@ -188,16 +140,16 @@ class VertexAccessor final {
|
|||||||
|
|
||||||
auto OutEdges(storage::v3::View view, const std::vector<storage::v3::EdgeTypeId> &edge_types,
|
auto OutEdges(storage::v3::View view, const std::vector<storage::v3::EdgeTypeId> &edge_types,
|
||||||
const VertexAccessor &dest) const
|
const VertexAccessor &dest) const
|
||||||
-> storage::v3::Result<decltype(iter::imap(MakeEdgeAccessor, *impl_.OutEdges(view)))> {
|
-> storage::v3::ShardResult<decltype(iter::imap(MakeEdgeAccessor, *impl_.OutEdges(view)))> {
|
||||||
const auto dest_id = dest.impl_.Id(view).GetValue();
|
const auto dest_id = dest.impl_.Id(view).GetValue();
|
||||||
auto maybe_edges = impl_.OutEdges(view, edge_types, &dest_id);
|
auto maybe_edges = impl_.OutEdges(view, edge_types, &dest_id);
|
||||||
if (maybe_edges.HasError()) return maybe_edges.GetError();
|
if (maybe_edges.HasError()) return maybe_edges.GetError();
|
||||||
return iter::imap(MakeEdgeAccessor, std::move(*maybe_edges));
|
return iter::imap(MakeEdgeAccessor, std::move(*maybe_edges));
|
||||||
}
|
}
|
||||||
|
|
||||||
storage::v3::Result<size_t> InDegree(storage::v3::View view) const { return impl_.InDegree(view); }
|
storage::v3::ShardResult<size_t> InDegree(storage::v3::View view) const { return impl_.InDegree(view); }
|
||||||
|
|
||||||
storage::v3::Result<size_t> OutDegree(storage::v3::View view) const { return impl_.OutDegree(view); }
|
storage::v3::ShardResult<size_t> OutDegree(storage::v3::View view) const { return impl_.OutDegree(view); }
|
||||||
|
|
||||||
// TODO(jbajic) Fix Remove Gid
|
// TODO(jbajic) Fix Remove Gid
|
||||||
static int64_t CypherId() { return 1; }
|
static int64_t CypherId() { return 1; }
|
||||||
|
@ -224,12 +224,4 @@ class VersionInfoInMulticommandTxException : public QueryException {
|
|||||||
: QueryException("Version info query not allowed in multicommand transactions.") {}
|
: QueryException("Version info query not allowed in multicommand transactions.") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* An exception for an illegal operation that violates schema
|
|
||||||
*/
|
|
||||||
class SchemaViolationException : public QueryRuntimeException {
|
|
||||||
public:
|
|
||||||
using QueryRuntimeException::QueryRuntimeException;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace memgraph::query::v2
|
} // namespace memgraph::query::v2
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include <cppitertools/chain.hpp>
|
#include <cppitertools/chain.hpp>
|
||||||
#include <cppitertools/imap.hpp>
|
#include <cppitertools/imap.hpp>
|
||||||
|
|
||||||
|
#include "common/errors.hpp"
|
||||||
#include "expr/ast/pretty_print_ast_to_original_expression.hpp"
|
#include "expr/ast/pretty_print_ast_to_original_expression.hpp"
|
||||||
#include "expr/exceptions.hpp"
|
#include "expr/exceptions.hpp"
|
||||||
#include "query/exceptions.hpp"
|
#include "query/exceptions.hpp"
|
||||||
@ -563,27 +564,6 @@ UniqueCursorPtr ScanAllById::MakeCursor(utils::MemoryResource *mem) const {
|
|||||||
std::move(vertices), "ScanAllById");
|
std::move(vertices), "ScanAllById");
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
template <class TEdges>
|
|
||||||
auto UnwrapEdgesResult(storage::v3::Result<TEdges> &&result) {
|
|
||||||
if (result.HasError()) {
|
|
||||||
switch (result.GetError()) {
|
|
||||||
case storage::v3::Error::DELETED_OBJECT:
|
|
||||||
throw QueryRuntimeException("Trying to get relationships of a deleted node.");
|
|
||||||
case storage::v3::Error::NONEXISTENT_OBJECT:
|
|
||||||
throw query::v2::QueryRuntimeException("Trying to get relationships from a node that doesn't exist.");
|
|
||||||
case storage::v3::Error::VERTEX_HAS_EDGES:
|
|
||||||
case storage::v3::Error::SERIALIZATION_ERROR:
|
|
||||||
case storage::v3::Error::PROPERTIES_DISABLED:
|
|
||||||
throw QueryRuntimeException("Unexpected error when accessing relationships.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return std::move(*result);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
Expand::Expand(const std::shared_ptr<LogicalOperator> &input, Symbol input_symbol, Symbol node_symbol,
|
Expand::Expand(const std::shared_ptr<LogicalOperator> &input, Symbol input_symbol, Symbol node_symbol,
|
||||||
Symbol edge_symbol, EdgeAtom::Direction direction,
|
Symbol edge_symbol, EdgeAtom::Direction direction,
|
||||||
const std::vector<storage::v3::EdgeTypeId> &edge_types, bool existing_node, storage::v3::View view)
|
const std::vector<storage::v3::EdgeTypeId> &edge_types, bool existing_node, storage::v3::View view)
|
||||||
@ -836,45 +816,9 @@ std::vector<Symbol> SetProperties::ModifiedSymbols(const SymbolTable &table) con
|
|||||||
SetProperties::SetPropertiesCursor::SetPropertiesCursor(const SetProperties &self, utils::MemoryResource *mem)
|
SetProperties::SetPropertiesCursor::SetPropertiesCursor(const SetProperties &self, utils::MemoryResource *mem)
|
||||||
: self_(self), input_cursor_(self.input_->MakeCursor(mem)) {}
|
: self_(self), input_cursor_(self.input_->MakeCursor(mem)) {}
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
concept AccessorWithProperties = requires(T value, storage::v3::PropertyId property_id,
|
|
||||||
storage::v3::PropertyValue property_value) {
|
|
||||||
{
|
|
||||||
value.ClearProperties()
|
|
||||||
} -> std::same_as<storage::v3::Result<std::map<storage::v3::PropertyId, storage::v3::PropertyValue>>>;
|
|
||||||
{value.SetProperty(property_id, property_value)};
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
bool SetProperties::SetPropertiesCursor::Pull(Frame &frame, ExecutionContext &context) {
|
bool SetProperties::SetPropertiesCursor::Pull(Frame &frame, ExecutionContext &context) {
|
||||||
SCOPED_PROFILE_OP("SetProperties");
|
SCOPED_PROFILE_OP("SetProperties");
|
||||||
return false;
|
return false;
|
||||||
// if (!input_cursor_->Pull(frame, context)) return false;
|
|
||||||
//
|
|
||||||
// TypedValue &lhs = frame[self_.input_symbol_];
|
|
||||||
//
|
|
||||||
// // Set, just like Create needs to see the latest changes.
|
|
||||||
// ExpressionEvaluator evaluator(&frame, context.symbol_table, context.evaluation_context, context.db_accessor,
|
|
||||||
// storage::v3::View::NEW);
|
|
||||||
// TypedValue rhs = self_.rhs_->Accept(evaluator);
|
|
||||||
//
|
|
||||||
// switch (lhs.type()) {
|
|
||||||
// case TypedValue::Type::Vertex:
|
|
||||||
// SetPropertiesOnRecord(&lhs.ValueVertex(), rhs, self_.op_, &context);
|
|
||||||
// break;
|
|
||||||
// case TypedValue::Type::Edge:
|
|
||||||
// SetPropertiesOnRecord(&lhs.ValueEdge(), rhs, self_.op_, &context);
|
|
||||||
// break;
|
|
||||||
// case TypedValue::Type::Null:
|
|
||||||
// // Skip setting properties on Null (can occur in optional match).
|
|
||||||
// break;
|
|
||||||
// default:
|
|
||||||
// throw QueryRuntimeException("Properties can only be set on edges and vertices.");
|
|
||||||
// }
|
|
||||||
// return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetProperties::SetPropertiesCursor::Shutdown() { input_cursor_->Shutdown(); }
|
void SetProperties::SetPropertiesCursor::Shutdown() { input_cursor_->Shutdown(); }
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include "coordinator/hybrid_logical_clock.hpp"
|
#include "coordinator/hybrid_logical_clock.hpp"
|
||||||
#include "storage/v3/id_types.hpp"
|
#include "storage/v3/id_types.hpp"
|
||||||
#include "storage/v3/property_value.hpp"
|
#include "storage/v3/property_value.hpp"
|
||||||
|
#include "storage/v3/result.hpp"
|
||||||
|
|
||||||
namespace memgraph::msgs {
|
namespace memgraph::msgs {
|
||||||
|
|
||||||
@ -317,6 +318,11 @@ struct Value {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ShardError {
|
||||||
|
common::ErrorCode code;
|
||||||
|
std::string message;
|
||||||
|
};
|
||||||
|
|
||||||
struct Expression {
|
struct Expression {
|
||||||
std::string expression;
|
std::string expression;
|
||||||
};
|
};
|
||||||
@ -361,7 +367,7 @@ struct ScanResultRow {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct ScanVerticesResponse {
|
struct ScanVerticesResponse {
|
||||||
bool success;
|
std::optional<ShardError> error;
|
||||||
std::optional<VertexId> next_start_id;
|
std::optional<VertexId> next_start_id;
|
||||||
std::vector<ScanResultRow> results;
|
std::vector<ScanResultRow> results;
|
||||||
};
|
};
|
||||||
@ -381,7 +387,7 @@ struct GetPropertiesRequest {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct GetPropertiesResponse {
|
struct GetPropertiesResponse {
|
||||||
bool success;
|
std::optional<ShardError> error;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class EdgeDirection : uint8_t { OUT = 1, IN = 2, BOTH = 3 };
|
enum class EdgeDirection : uint8_t { OUT = 1, IN = 2, BOTH = 3 };
|
||||||
@ -403,7 +409,9 @@ struct ExpandOneRequest {
|
|||||||
std::vector<std::string> vertex_expressions;
|
std::vector<std::string> vertex_expressions;
|
||||||
std::vector<std::string> edge_expressions;
|
std::vector<std::string> edge_expressions;
|
||||||
|
|
||||||
std::optional<std::vector<OrderBy>> order_by;
|
std::vector<OrderBy> order_by_vertices;
|
||||||
|
std::vector<OrderBy> order_by_edges;
|
||||||
|
|
||||||
// Limit the edges or the vertices?
|
// Limit the edges or the vertices?
|
||||||
std::optional<size_t> limit;
|
std::optional<size_t> limit;
|
||||||
std::vector<std::string> filters;
|
std::vector<std::string> filters;
|
||||||
@ -446,14 +454,16 @@ struct ExpandOneResultRow {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct ExpandOneResponse {
|
struct ExpandOneResponse {
|
||||||
bool success;
|
std::optional<ShardError> error;
|
||||||
std::vector<ExpandOneResultRow> result;
|
std::vector<ExpandOneResultRow> result;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct UpdateVertexProp {
|
struct UpdateVertex {
|
||||||
PrimaryKey primary_key;
|
PrimaryKey primary_key;
|
||||||
// This should be a map
|
// Labels are first added and then removed from vertices
|
||||||
std::vector<std::pair<PropertyId, Value>> property_updates;
|
std::vector<LabelId> add_labels;
|
||||||
|
std::vector<LabelId> remove_labels;
|
||||||
|
std::map<PropertyId, Value> property_updates;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct UpdateEdgeProp {
|
struct UpdateEdgeProp {
|
||||||
@ -480,7 +490,7 @@ struct CreateVerticesRequest {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct CreateVerticesResponse {
|
struct CreateVerticesResponse {
|
||||||
bool success;
|
std::optional<ShardError> error;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DeleteVerticesRequest {
|
struct DeleteVerticesRequest {
|
||||||
@ -491,16 +501,16 @@ struct DeleteVerticesRequest {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct DeleteVerticesResponse {
|
struct DeleteVerticesResponse {
|
||||||
bool success;
|
std::optional<ShardError> error;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct UpdateVerticesRequest {
|
struct UpdateVerticesRequest {
|
||||||
Hlc transaction_id;
|
Hlc transaction_id;
|
||||||
std::vector<UpdateVertexProp> new_properties;
|
std::vector<UpdateVertex> update_vertices;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct UpdateVerticesResponse {
|
struct UpdateVerticesResponse {
|
||||||
bool success;
|
std::optional<ShardError> error;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -522,7 +532,7 @@ struct CreateExpandRequest {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct CreateExpandResponse {
|
struct CreateExpandResponse {
|
||||||
bool success;
|
std::optional<ShardError> error;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DeleteEdgesRequest {
|
struct DeleteEdgesRequest {
|
||||||
@ -531,7 +541,7 @@ struct DeleteEdgesRequest {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct DeleteEdgesResponse {
|
struct DeleteEdgesResponse {
|
||||||
bool success;
|
std::optional<ShardError> error;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct UpdateEdgesRequest {
|
struct UpdateEdgesRequest {
|
||||||
@ -540,7 +550,7 @@ struct UpdateEdgesRequest {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct UpdateEdgesResponse {
|
struct UpdateEdgesResponse {
|
||||||
bool success;
|
std::optional<ShardError> error;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CommitRequest {
|
struct CommitRequest {
|
||||||
@ -549,7 +559,7 @@ struct CommitRequest {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct CommitResponse {
|
struct CommitResponse {
|
||||||
bool success;
|
std::optional<ShardError> error;
|
||||||
};
|
};
|
||||||
|
|
||||||
using ReadRequests = std::variant<ExpandOneRequest, GetPropertiesRequest, ScanVerticesRequest>;
|
using ReadRequests = std::variant<ExpandOneRequest, GetPropertiesRequest, ScanVerticesRequest>;
|
||||||
|
@ -209,7 +209,7 @@ class ShardRequestManager : public ShardRequestManagerInterface {
|
|||||||
}
|
}
|
||||||
WriteResponses write_response_variant = commit_response.GetValue();
|
WriteResponses write_response_variant = commit_response.GetValue();
|
||||||
auto &response = std::get<CommitResponse>(write_response_variant);
|
auto &response = std::get<CommitResponse>(write_response_variant);
|
||||||
if (!response.success) {
|
if (response.error) {
|
||||||
throw std::runtime_error("Commit request did not succeed");
|
throw std::runtime_error("Commit request did not succeed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -314,7 +314,7 @@ class ShardRequestManager : public ShardRequestManagerInterface {
|
|||||||
WriteResponses response_variant = write_response_result.GetValue();
|
WriteResponses response_variant = write_response_result.GetValue();
|
||||||
CreateExpandResponse mapped_response = std::get<CreateExpandResponse>(response_variant);
|
CreateExpandResponse mapped_response = std::get<CreateExpandResponse>(response_variant);
|
||||||
|
|
||||||
if (!mapped_response.success) {
|
if (mapped_response.error) {
|
||||||
throw std::runtime_error("CreateExpand request did not succeed");
|
throw std::runtime_error("CreateExpand request did not succeed");
|
||||||
}
|
}
|
||||||
responses.push_back(mapped_response);
|
responses.push_back(mapped_response);
|
||||||
@ -616,7 +616,7 @@ class ShardRequestManager : public ShardRequestManagerInterface {
|
|||||||
WriteResponses response_variant = poll_result->GetValue();
|
WriteResponses response_variant = poll_result->GetValue();
|
||||||
auto response = std::get<CreateVerticesResponse>(response_variant);
|
auto response = std::get<CreateVerticesResponse>(response_variant);
|
||||||
|
|
||||||
if (!response.success) {
|
if (response.error) {
|
||||||
throw std::runtime_error("CreateVertices request did not succeed");
|
throw std::runtime_error("CreateVertices request did not succeed");
|
||||||
}
|
}
|
||||||
responses.push_back(response);
|
responses.push_back(response);
|
||||||
@ -652,7 +652,7 @@ class ShardRequestManager : public ShardRequestManagerInterface {
|
|||||||
// Currently a boolean flag for signaling the overall success of the
|
// Currently a boolean flag for signaling the overall success of the
|
||||||
// ExpandOne request does not exist. But it should, so here we assume
|
// ExpandOne request does not exist. But it should, so here we assume
|
||||||
// that it is already in place.
|
// that it is already in place.
|
||||||
if (!response.success) {
|
if (response.error) {
|
||||||
throw std::runtime_error("ExpandOne request did not succeed");
|
throw std::runtime_error("ExpandOne request did not succeed");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -695,7 +695,7 @@ class ShardRequestManager : public ShardRequestManagerInterface {
|
|||||||
|
|
||||||
ReadResponses read_response_variant = await_result->GetValue();
|
ReadResponses read_response_variant = await_result->GetValue();
|
||||||
auto response = std::get<ScanVerticesResponse>(read_response_variant);
|
auto response = std::get<ScanVerticesResponse>(read_response_variant);
|
||||||
if (!response.success) {
|
if (response.error) {
|
||||||
throw std::runtime_error("ScanAll request did not succeed");
|
throw std::runtime_error("ScanAll request did not succeed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,15 +97,15 @@ bool LastCommittedVersionHasLabelProperty(const Vertex &vertex, LabelId label, c
|
|||||||
if (delta->label == label) {
|
if (delta->label == label) {
|
||||||
MG_ASSERT(!has_label, "Invalid database state!");
|
MG_ASSERT(!has_label, "Invalid database state!");
|
||||||
has_label = true;
|
has_label = true;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
case Delta::Action::REMOVE_LABEL: {
|
case Delta::Action::REMOVE_LABEL: {
|
||||||
if (delta->label == label) {
|
if (delta->label == label) {
|
||||||
MG_ASSERT(has_label, "Invalid database state!");
|
MG_ASSERT(has_label, "Invalid database state!");
|
||||||
has_label = false;
|
has_label = false;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
case Delta::Action::ADD_IN_EDGE:
|
case Delta::Action::ADD_IN_EDGE:
|
||||||
case Delta::Action::ADD_OUT_EDGE:
|
case Delta::Action::ADD_OUT_EDGE:
|
||||||
|
@ -78,7 +78,7 @@ class DbAccessor final {
|
|||||||
return VerticesIterable(accessor_->Vertices(label, property, lower, upper, view));
|
return VerticesIterable(accessor_->Vertices(label, property, lower, upper, view));
|
||||||
}
|
}
|
||||||
|
|
||||||
storage::v3::Result<EdgeAccessor> InsertEdge(VertexAccessor *from, VertexAccessor *to,
|
storage::v3::ShardResult<EdgeAccessor> InsertEdge(VertexAccessor *from, VertexAccessor *to,
|
||||||
const storage::v3::EdgeTypeId &edge_type) {
|
const storage::v3::EdgeTypeId &edge_type) {
|
||||||
static constexpr auto kDummyGid = storage::v3::Gid::FromUint(0);
|
static constexpr auto kDummyGid = storage::v3::Gid::FromUint(0);
|
||||||
auto maybe_edge = accessor_->CreateEdge(from->Id(storage::v3::View::NEW).GetValue(),
|
auto maybe_edge = accessor_->CreateEdge(from->Id(storage::v3::View::NEW).GetValue(),
|
||||||
@ -87,8 +87,8 @@ class DbAccessor final {
|
|||||||
return EdgeAccessor(*maybe_edge);
|
return EdgeAccessor(*maybe_edge);
|
||||||
}
|
}
|
||||||
|
|
||||||
storage::v3::Result<std::optional<EdgeAccessor>> RemoveEdge(EdgeAccessor *edge) {
|
storage::v3::ShardResult<std::optional<EdgeAccessor>> RemoveEdge(EdgeAccessor *edge) {
|
||||||
auto res = accessor_->DeleteEdge(edge->From(), edge->To(), edge->Gid());
|
auto res = accessor_->DeleteEdge(edge->FromVertex(), edge->ToVertex(), edge->Gid());
|
||||||
if (res.HasError()) {
|
if (res.HasError()) {
|
||||||
return res.GetError();
|
return res.GetError();
|
||||||
}
|
}
|
||||||
@ -101,7 +101,7 @@ class DbAccessor final {
|
|||||||
return std::make_optional<EdgeAccessor>(*value);
|
return std::make_optional<EdgeAccessor>(*value);
|
||||||
}
|
}
|
||||||
|
|
||||||
storage::v3::Result<std::optional<std::pair<VertexAccessor, std::vector<EdgeAccessor>>>> DetachRemoveVertex(
|
storage::v3::ShardResult<std::optional<std::pair<VertexAccessor, std::vector<EdgeAccessor>>>> DetachRemoveVertex(
|
||||||
VertexAccessor *vertex_accessor) {
|
VertexAccessor *vertex_accessor) {
|
||||||
using ReturnType = std::pair<VertexAccessor, std::vector<EdgeAccessor>>;
|
using ReturnType = std::pair<VertexAccessor, std::vector<EdgeAccessor>>;
|
||||||
|
|
||||||
@ -125,7 +125,7 @@ class DbAccessor final {
|
|||||||
return std::make_optional<ReturnType>(vertex, std::move(deleted_edges));
|
return std::make_optional<ReturnType>(vertex, std::move(deleted_edges));
|
||||||
}
|
}
|
||||||
|
|
||||||
storage::v3::Result<std::optional<VertexAccessor>> RemoveVertex(VertexAccessor *vertex_accessor) {
|
storage::v3::ShardResult<std::optional<VertexAccessor>> RemoveVertex(VertexAccessor *vertex_accessor) {
|
||||||
auto res = accessor_->DeleteVertex(vertex_accessor);
|
auto res = accessor_->DeleteVertex(vertex_accessor);
|
||||||
if (res.HasError()) {
|
if (res.HasError()) {
|
||||||
return res.GetError();
|
return res.GetError();
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include "storage/v3/id_types.hpp"
|
#include "storage/v3/id_types.hpp"
|
||||||
#include "storage/v3/property_store.hpp"
|
#include "storage/v3/property_store.hpp"
|
||||||
#include "storage/v3/property_value.hpp"
|
#include "storage/v3/property_value.hpp"
|
||||||
|
#include "storage/v3/result.hpp"
|
||||||
#include "storage/v3/view.hpp"
|
#include "storage/v3/view.hpp"
|
||||||
#include "utils/memory.hpp"
|
#include "utils/memory.hpp"
|
||||||
|
|
||||||
@ -87,6 +88,6 @@ struct EvaluationContext {
|
|||||||
using ExpressionEvaluator =
|
using ExpressionEvaluator =
|
||||||
memgraph::expr::ExpressionEvaluator<TypedValue, EvaluationContext, DbAccessor, storage::v3::View,
|
memgraph::expr::ExpressionEvaluator<TypedValue, EvaluationContext, DbAccessor, storage::v3::View,
|
||||||
storage::v3::LabelId, storage::v3::PropertyStore, PropertyToTypedValueConverter,
|
storage::v3::LabelId, storage::v3::PropertyStore, PropertyToTypedValueConverter,
|
||||||
memgraph::storage::v3::Error>;
|
common::ErrorCode>;
|
||||||
|
|
||||||
} // namespace memgraph::storage::v3
|
} // namespace memgraph::storage::v3
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
#include "storage/v3/mvcc.hpp"
|
#include "storage/v3/mvcc.hpp"
|
||||||
#include "storage/v3/property_value.hpp"
|
#include "storage/v3/property_value.hpp"
|
||||||
|
#include "storage/v3/result.hpp"
|
||||||
#include "storage/v3/schema_validator.hpp"
|
#include "storage/v3/schema_validator.hpp"
|
||||||
#include "storage/v3/vertex_accessor.hpp"
|
#include "storage/v3/vertex_accessor.hpp"
|
||||||
#include "utils/memory_tracker.hpp"
|
#include "utils/memory_tracker.hpp"
|
||||||
@ -54,13 +55,13 @@ const VertexId &EdgeAccessor::From() const { return from_vertex_; }
|
|||||||
|
|
||||||
const VertexId &EdgeAccessor::To() const { return to_vertex_; }
|
const VertexId &EdgeAccessor::To() const { return to_vertex_; }
|
||||||
|
|
||||||
Result<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;
|
||||||
if (!config_.properties_on_edges) return Error::PROPERTIES_DISABLED;
|
if (!config_.properties_on_edges) return SHARD_ERROR(ErrorCode::PROPERTIES_DISABLED);
|
||||||
|
|
||||||
if (!PrepareForWrite(transaction_, edge_.ptr)) return Error::SERIALIZATION_ERROR;
|
if (!PrepareForWrite(transaction_, edge_.ptr)) return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR);
|
||||||
|
|
||||||
if (edge_.ptr->deleted) return Error::DELETED_OBJECT;
|
if (edge_.ptr->deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
|
||||||
|
|
||||||
auto current_value = edge_.ptr->properties.GetProperty(property);
|
auto current_value = edge_.ptr->properties.GetProperty(property);
|
||||||
// We could skip setting the value if the previous one is the same to the new
|
// We could skip setting the value if the previous one is the same to the new
|
||||||
@ -75,12 +76,12 @@ Result<PropertyValue> EdgeAccessor::SetProperty(PropertyId property, const Prope
|
|||||||
return std::move(current_value);
|
return std::move(current_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<std::map<PropertyId, PropertyValue>> EdgeAccessor::ClearProperties() {
|
ShardResult<std::map<PropertyId, PropertyValue>> EdgeAccessor::ClearProperties() {
|
||||||
if (!config_.properties_on_edges) return Error::PROPERTIES_DISABLED;
|
if (!config_.properties_on_edges) return SHARD_ERROR(ErrorCode::PROPERTIES_DISABLED);
|
||||||
|
|
||||||
if (!PrepareForWrite(transaction_, edge_.ptr)) return Error::SERIALIZATION_ERROR;
|
if (!PrepareForWrite(transaction_, edge_.ptr)) return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR);
|
||||||
|
|
||||||
if (edge_.ptr->deleted) return Error::DELETED_OBJECT;
|
if (edge_.ptr->deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
|
||||||
|
|
||||||
auto properties = edge_.ptr->properties.Properties();
|
auto properties = edge_.ptr->properties.Properties();
|
||||||
for (const auto &property : properties) {
|
for (const auto &property : properties) {
|
||||||
@ -92,11 +93,11 @@ Result<std::map<PropertyId, PropertyValue>> EdgeAccessor::ClearProperties() {
|
|||||||
return std::move(properties);
|
return std::move(properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<PropertyValue> EdgeAccessor::GetProperty(View view, PropertyId property) const {
|
ShardResult<PropertyValue> EdgeAccessor::GetProperty(View view, PropertyId property) const {
|
||||||
return GetProperty(property, view);
|
return GetProperty(property, view);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<PropertyValue> EdgeAccessor::GetProperty(PropertyId property, View view) const {
|
ShardResult<PropertyValue> EdgeAccessor::GetProperty(PropertyId property, View view) const {
|
||||||
if (!config_.properties_on_edges) return PropertyValue();
|
if (!config_.properties_on_edges) return PropertyValue();
|
||||||
auto exists = true;
|
auto exists = true;
|
||||||
auto deleted = edge_.ptr->deleted;
|
auto deleted = edge_.ptr->deleted;
|
||||||
@ -128,12 +129,12 @@ Result<PropertyValue> EdgeAccessor::GetProperty(PropertyId property, View view)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (!exists) return Error::NONEXISTENT_OBJECT;
|
if (!exists) return SHARD_ERROR(ErrorCode::NONEXISTENT_OBJECT);
|
||||||
if (!for_deleted_ && deleted) return Error::DELETED_OBJECT;
|
if (!for_deleted_ && deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
|
||||||
return std::move(value);
|
return std::move(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<std::map<PropertyId, PropertyValue>> EdgeAccessor::Properties(View view) const {
|
ShardResult<std::map<PropertyId, PropertyValue>> EdgeAccessor::Properties(View view) const {
|
||||||
if (!config_.properties_on_edges) return std::map<PropertyId, PropertyValue>{};
|
if (!config_.properties_on_edges) return std::map<PropertyId, PropertyValue>{};
|
||||||
auto exists = true;
|
auto exists = true;
|
||||||
auto deleted = edge_.ptr->deleted;
|
auto deleted = edge_.ptr->deleted;
|
||||||
@ -174,8 +175,8 @@ Result<std::map<PropertyId, PropertyValue>> EdgeAccessor::Properties(View view)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (!exists) return Error::NONEXISTENT_OBJECT;
|
if (!exists) return SHARD_ERROR(ErrorCode::NONEXISTENT_OBJECT);
|
||||||
if (!for_deleted_ && deleted) return Error::DELETED_OBJECT;
|
if (!for_deleted_ && deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
|
||||||
return std::move(properties);
|
return std::move(properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,19 +56,19 @@ class EdgeAccessor final {
|
|||||||
|
|
||||||
/// Set a property value and return the old value.
|
/// Set a property value and return the old value.
|
||||||
/// @throw std::bad_alloc
|
/// @throw std::bad_alloc
|
||||||
Result<PropertyValue> SetProperty(PropertyId property, const PropertyValue &value);
|
ShardResult<PropertyValue> SetProperty(PropertyId property, const PropertyValue &value);
|
||||||
|
|
||||||
/// Remove all properties and return old values for each removed property.
|
/// Remove all properties and return old values for each removed property.
|
||||||
/// @throw std::bad_alloc
|
/// @throw std::bad_alloc
|
||||||
Result<std::map<PropertyId, PropertyValue>> ClearProperties();
|
ShardResult<std::map<PropertyId, PropertyValue>> ClearProperties();
|
||||||
|
|
||||||
/// @throw std::bad_alloc
|
/// @throw std::bad_alloc
|
||||||
Result<PropertyValue> GetProperty(PropertyId property, View view) const;
|
ShardResult<PropertyValue> GetProperty(PropertyId property, View view) const;
|
||||||
|
|
||||||
Result<PropertyValue> GetProperty(View view, PropertyId property) const;
|
ShardResult<PropertyValue> GetProperty(View view, PropertyId property) const;
|
||||||
|
|
||||||
/// @throw std::bad_alloc
|
/// @throw std::bad_alloc
|
||||||
Result<std::map<PropertyId, PropertyValue>> Properties(View view) const;
|
ShardResult<std::map<PropertyId, PropertyValue>> Properties(View view) const;
|
||||||
|
|
||||||
Gid Gid() const noexcept {
|
Gid Gid() const noexcept {
|
||||||
if (config_.properties_on_edges) {
|
if (config_.properties_on_edges) {
|
||||||
|
@ -164,7 +164,7 @@ std::any ParseExpression(const std::string &expr, memgraph::expr::AstStorage &st
|
|||||||
return visitor.visit(ast);
|
return visitor.visit(ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
TypedValue ComputeExpression(DbAccessor &dba, const std::optional<memgraph::storage::v3::VertexAccessor> &v_acc,
|
TypedValue ComputeExpression(DbAccessor &dba, const memgraph::storage::v3::VertexAccessor &v_acc,
|
||||||
const std::optional<memgraph::storage::v3::EdgeAccessor> &e_acc,
|
const std::optional<memgraph::storage::v3::EdgeAccessor> &e_acc,
|
||||||
const std::string &expression, std::string_view node_name, std::string_view edge_name) {
|
const std::string &expression, std::string_view node_name, std::string_view edge_name) {
|
||||||
AstStorage storage;
|
AstStorage storage;
|
||||||
@ -191,10 +191,11 @@ TypedValue ComputeExpression(DbAccessor &dba, const std::optional<memgraph::stor
|
|||||||
return position_symbol_pair.second.name() == node_name;
|
return position_symbol_pair.second.name() == node_name;
|
||||||
}) != symbol_table.table().end());
|
}) != symbol_table.table().end());
|
||||||
|
|
||||||
frame[symbol_table.at(node_identifier)] = *v_acc;
|
frame[symbol_table.at(node_identifier)] = v_acc;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (edge_identifier.symbol_pos_ != -1) {
|
if (edge_identifier.symbol_pos_ != -1) {
|
||||||
|
MG_ASSERT(e_acc.has_value());
|
||||||
MG_ASSERT(std::find_if(symbol_table.table().begin(), symbol_table.table().end(),
|
MG_ASSERT(std::find_if(symbol_table.table().begin(), symbol_table.table().end(),
|
||||||
[&edge_name](const std::pair<int32_t, Symbol> &position_symbol_pair) {
|
[&edge_name](const std::pair<int32_t, Symbol> &position_symbol_pair) {
|
||||||
return position_symbol_pair.second.name() == edge_name;
|
return position_symbol_pair.second.name() == edge_name;
|
||||||
|
@ -9,6 +9,8 @@
|
|||||||
// by the Apache License, Version 2.0, included in the file
|
// by the Apache License, Version 2.0, included in the file
|
||||||
// licenses/APL.txt.
|
// licenses/APL.txt.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "db_accessor.hpp"
|
#include "db_accessor.hpp"
|
||||||
@ -48,8 +50,7 @@ auto Eval(TExpression *expr, EvaluationContext &ctx, AstStorage &storage, Expres
|
|||||||
|
|
||||||
std::any ParseExpression(const std::string &expr, AstStorage &storage);
|
std::any ParseExpression(const std::string &expr, AstStorage &storage);
|
||||||
|
|
||||||
TypedValue ComputeExpression(DbAccessor &dba, const std::optional<VertexAccessor> &v_acc,
|
TypedValue ComputeExpression(DbAccessor &dba, const VertexAccessor &v_acc, const std::optional<EdgeAccessor> &e_acc,
|
||||||
const std::optional<EdgeAccessor> &e_acc, const std::string &expression,
|
const std::string &expression, std::string_view node_name, std::string_view edge_name);
|
||||||
std::string_view node_name, std::string_view edge_name);
|
|
||||||
|
|
||||||
} // namespace memgraph::storage::v3
|
} // namespace memgraph::storage::v3
|
||||||
|
@ -13,54 +13,436 @@
|
|||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "pretty_print_ast_to_original_expression.hpp"
|
|
||||||
#include "storage/v3/bindings/db_accessor.hpp"
|
#include "storage/v3/bindings/db_accessor.hpp"
|
||||||
|
#include "storage/v3/bindings/pretty_print_ast_to_original_expression.hpp"
|
||||||
#include "storage/v3/expr.hpp"
|
#include "storage/v3/expr.hpp"
|
||||||
|
#include "storage/v3/result.hpp"
|
||||||
|
#include "storage/v3/value_conversions.hpp"
|
||||||
|
|
||||||
namespace memgraph::storage::v3 {
|
namespace memgraph::storage::v3 {
|
||||||
|
using msgs::Label;
|
||||||
|
using msgs::PropertyId;
|
||||||
|
|
||||||
std::vector<Element> OrderByElements(Shard::Accessor &acc, DbAccessor &dba, VerticesIterable &vertices_iterable,
|
using conversions::ConvertPropertyVector;
|
||||||
std::vector<msgs::OrderBy> &order_bys) {
|
using conversions::FromPropertyValueToValue;
|
||||||
std::vector<Element> ordered;
|
using conversions::ToMsgsVertexId;
|
||||||
ordered.reserve(acc.ApproximateVertexCount());
|
|
||||||
std::vector<Ordering> ordering;
|
namespace {
|
||||||
ordering.reserve(order_bys.size());
|
|
||||||
for (const auto &order : order_bys) {
|
using AllEdgePropertyDataStucture = std::map<PropertyId, msgs::Value>;
|
||||||
switch (order.direction) {
|
using SpecificEdgePropertyDataStucture = std::vector<msgs::Value>;
|
||||||
case memgraph::msgs::OrderingDirection::ASCENDING: {
|
|
||||||
ordering.push_back(Ordering::ASC);
|
using AllEdgeProperties = std::tuple<msgs::VertexId, msgs::Gid, AllEdgePropertyDataStucture>;
|
||||||
|
using SpecificEdgeProperties = std::tuple<msgs::VertexId, msgs::Gid, SpecificEdgePropertyDataStucture>;
|
||||||
|
|
||||||
|
using SpecificEdgePropertiesVector = std::vector<SpecificEdgeProperties>;
|
||||||
|
using AllEdgePropertiesVector = std::vector<AllEdgeProperties>;
|
||||||
|
|
||||||
|
struct VertexIdCmpr {
|
||||||
|
bool operator()(const storage::v3::VertexId *lhs, const storage::v3::VertexId *rhs) const { return *lhs < *rhs; }
|
||||||
|
};
|
||||||
|
|
||||||
|
std::optional<std::map<PropertyId, Value>> PrimaryKeysFromAccessor(const VertexAccessor &acc, View view,
|
||||||
|
const Schemas::Schema &schema) {
|
||||||
|
std::map<PropertyId, Value> ret;
|
||||||
|
auto props = acc.Properties(view);
|
||||||
|
auto maybe_pk = acc.PrimaryKey(view);
|
||||||
|
if (maybe_pk.HasError()) {
|
||||||
|
spdlog::debug("Encountered an error while trying to get vertex primary key.");
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
auto &pk = maybe_pk.GetValue();
|
||||||
|
MG_ASSERT(schema.second.size() == pk.size(), "PrimaryKey size does not match schema!");
|
||||||
|
for (size_t i{0}; i < schema.second.size(); ++i) {
|
||||||
|
ret.emplace(schema.second[i].property_id, FromPropertyValueToValue(std::move(pk[i])));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ShardResult<std::vector<msgs::Label>> FillUpSourceVertexSecondaryLabels(const std::optional<VertexAccessor> &v_acc,
|
||||||
|
const msgs::ExpandOneRequest &req) {
|
||||||
|
auto secondary_labels = v_acc->Labels(View::NEW);
|
||||||
|
if (secondary_labels.HasError()) {
|
||||||
|
spdlog::debug("Encountered an error while trying to get the secondary labels of a vertex. Transaction id: {}",
|
||||||
|
req.transaction_id.logical_id);
|
||||||
|
return secondary_labels.GetError();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &sec_labels = secondary_labels.GetValue();
|
||||||
|
std::vector<msgs::Label> msgs_secondary_labels;
|
||||||
|
msgs_secondary_labels.reserve(sec_labels.size());
|
||||||
|
|
||||||
|
std::transform(sec_labels.begin(), sec_labels.end(), std::back_inserter(msgs_secondary_labels),
|
||||||
|
[](auto label_id) { return msgs::Label{.id = label_id}; });
|
||||||
|
|
||||||
|
return msgs_secondary_labels;
|
||||||
|
}
|
||||||
|
|
||||||
|
ShardResult<std::map<PropertyId, Value>> FillUpSourceVertexProperties(const std::optional<VertexAccessor> &v_acc,
|
||||||
|
const msgs::ExpandOneRequest &req,
|
||||||
|
storage::v3::View view,
|
||||||
|
const Schemas::Schema &schema) {
|
||||||
|
std::map<PropertyId, Value> src_vertex_properties;
|
||||||
|
|
||||||
|
if (!req.src_vertex_properties) {
|
||||||
|
auto props = v_acc->Properties(View::NEW);
|
||||||
|
if (props.HasError()) {
|
||||||
|
spdlog::debug("Encountered an error while trying to access vertex properties. Transaction id: {}",
|
||||||
|
req.transaction_id.logical_id);
|
||||||
|
return props.GetError();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &[key, val] : props.GetValue()) {
|
||||||
|
src_vertex_properties.insert(std::make_pair(key, FromPropertyValueToValue(std::move(val))));
|
||||||
|
}
|
||||||
|
auto pks = PrimaryKeysFromAccessor(*v_acc, view, schema);
|
||||||
|
if (pks) {
|
||||||
|
src_vertex_properties.merge(*pks);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (req.src_vertex_properties.value().empty()) {
|
||||||
|
// NOOP
|
||||||
|
} else {
|
||||||
|
for (const auto &prop : req.src_vertex_properties.value()) {
|
||||||
|
auto prop_val = v_acc->GetProperty(prop, View::OLD);
|
||||||
|
if (prop_val.HasError()) {
|
||||||
|
spdlog::debug("Encountered an error while trying to access vertex properties. Transaction id: {}",
|
||||||
|
req.transaction_id.logical_id);
|
||||||
|
return prop_val.GetError();
|
||||||
|
}
|
||||||
|
src_vertex_properties.insert(std::make_pair(prop, FromPropertyValueToValue(std::move(prop_val.GetValue()))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return src_vertex_properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
ShardResult<std::array<std::vector<EdgeAccessor>, 2>> FillUpConnectingEdges(
|
||||||
|
const std::optional<VertexAccessor> &v_acc, const msgs::ExpandOneRequest &req,
|
||||||
|
const EdgeUniquenessFunction &maybe_filter_based_on_edge_uniqueness) {
|
||||||
|
std::vector<EdgeTypeId> edge_types{};
|
||||||
|
edge_types.reserve(req.edge_types.size());
|
||||||
|
std::transform(req.edge_types.begin(), req.edge_types.end(), std::back_inserter(edge_types),
|
||||||
|
[](const msgs::EdgeType &edge_type) { return edge_type.id; });
|
||||||
|
|
||||||
|
std::vector<EdgeAccessor> in_edges;
|
||||||
|
std::vector<EdgeAccessor> out_edges;
|
||||||
|
|
||||||
|
switch (req.direction) {
|
||||||
|
case msgs::EdgeDirection::OUT: {
|
||||||
|
auto out_edges_result = v_acc->OutEdges(View::NEW, edge_types);
|
||||||
|
if (out_edges_result.HasError()) {
|
||||||
|
spdlog::debug("Encountered an error while trying to get out-going EdgeAccessors. Transaction id: {}",
|
||||||
|
req.transaction_id.logical_id);
|
||||||
|
return out_edges_result.GetError();
|
||||||
|
}
|
||||||
|
out_edges =
|
||||||
|
maybe_filter_based_on_edge_uniqueness(std::move(out_edges_result.GetValue()), msgs::EdgeDirection::OUT);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case memgraph::msgs::OrderingDirection::DESCENDING: {
|
case msgs::EdgeDirection::IN: {
|
||||||
ordering.push_back(Ordering::DESC);
|
auto in_edges_result = v_acc->InEdges(View::NEW, edge_types);
|
||||||
|
if (in_edges_result.HasError()) {
|
||||||
|
spdlog::debug(
|
||||||
|
"Encountered an error while trying to get in-going EdgeAccessors. Transaction id: {}"[req.transaction_id
|
||||||
|
.logical_id]);
|
||||||
|
return in_edges_result.GetError();
|
||||||
|
}
|
||||||
|
in_edges = maybe_filter_based_on_edge_uniqueness(std::move(in_edges_result.GetValue()), msgs::EdgeDirection::IN);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case msgs::EdgeDirection::BOTH: {
|
||||||
|
auto in_edges_result = v_acc->InEdges(View::NEW, edge_types);
|
||||||
|
if (in_edges_result.HasError()) {
|
||||||
|
spdlog::debug("Encountered an error while trying to get in-going EdgeAccessors. Transaction id: {}",
|
||||||
|
req.transaction_id.logical_id);
|
||||||
|
return in_edges_result.GetError();
|
||||||
|
}
|
||||||
|
in_edges = maybe_filter_based_on_edge_uniqueness(std::move(in_edges_result.GetValue()), msgs::EdgeDirection::IN);
|
||||||
|
auto out_edges_result = v_acc->OutEdges(View::NEW, edge_types);
|
||||||
|
if (out_edges_result.HasError()) {
|
||||||
|
spdlog::debug("Encountered an error while trying to get out-going EdgeAccessors. Transaction id: {}",
|
||||||
|
req.transaction_id.logical_id);
|
||||||
|
return out_edges_result.GetError();
|
||||||
|
}
|
||||||
|
out_edges =
|
||||||
|
maybe_filter_based_on_edge_uniqueness(std::move(out_edges_result.GetValue()), msgs::EdgeDirection::OUT);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
return std::array<std::vector<EdgeAccessor>, 2>{std::move(in_edges), std::move(out_edges)};
|
||||||
auto compare_typed_values = TypedValueVectorCompare(ordering);
|
}
|
||||||
for (auto it = vertices_iterable.begin(); it != vertices_iterable.end(); ++it) {
|
|
||||||
std::vector<TypedValue> properties_order_by;
|
|
||||||
properties_order_by.reserve(order_bys.size());
|
|
||||||
|
|
||||||
for (const auto &order_by : order_bys) {
|
template <bool are_in_edges>
|
||||||
const auto val =
|
ShardResult<void> FillEdges(const std::vector<EdgeAccessor> &edges, msgs::ExpandOneResultRow &row,
|
||||||
ComputeExpression(dba, *it, std::nullopt, order_by.expression.expression, expr::identifier_node_symbol, "");
|
const EdgeFiller &edge_filler) {
|
||||||
properties_order_by.push_back(val);
|
for (const auto &edge : edges) {
|
||||||
|
if (const auto res = edge_filler(edge, are_in_edges, row); res.HasError()) {
|
||||||
|
return res.GetError();
|
||||||
}
|
}
|
||||||
ordered.push_back({std::move(properties_order_by), *it});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::sort(ordered.begin(), ordered.end(), [compare_typed_values](const auto &pair1, const auto &pair2) {
|
return {};
|
||||||
return compare_typed_values(pair1.properties_order_by, pair2.properties_order_by);
|
}
|
||||||
|
|
||||||
|
}; // namespace
|
||||||
|
|
||||||
|
ShardResult<std::map<PropertyId, Value>> CollectSpecificPropertiesFromAccessor(const VertexAccessor &acc,
|
||||||
|
const std::vector<PropertyId> &props,
|
||||||
|
View view) {
|
||||||
|
std::map<PropertyId, Value> ret;
|
||||||
|
|
||||||
|
for (const auto &prop : props) {
|
||||||
|
auto result = acc.GetProperty(prop, view);
|
||||||
|
if (result.HasError()) {
|
||||||
|
spdlog::debug("Encountered an Error while trying to get a vertex property.");
|
||||||
|
return result.GetError();
|
||||||
|
}
|
||||||
|
auto &value = result.GetValue();
|
||||||
|
ret.emplace(std::make_pair(prop, FromPropertyValueToValue(std::move(value))));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<TypedValue> EvaluateVertexExpressions(DbAccessor &dba, const VertexAccessor &v_acc,
|
||||||
|
const std::vector<std::string> &expressions,
|
||||||
|
std::string_view node_name) {
|
||||||
|
std::vector<TypedValue> evaluated_expressions;
|
||||||
|
evaluated_expressions.reserve(expressions.size());
|
||||||
|
|
||||||
|
std::transform(expressions.begin(), expressions.end(), std::back_inserter(evaluated_expressions),
|
||||||
|
[&dba, &v_acc, &node_name](const auto &expression) {
|
||||||
|
return ComputeExpression(dba, v_acc, std::nullopt, expression, node_name, "");
|
||||||
});
|
});
|
||||||
return ordered;
|
|
||||||
|
return evaluated_expressions;
|
||||||
|
}
|
||||||
|
|
||||||
|
ShardResult<std::map<PropertyId, Value>> CollectAllPropertiesFromAccessor(const VertexAccessor &acc, View view,
|
||||||
|
const Schemas::Schema &schema) {
|
||||||
|
std::map<PropertyId, Value> ret;
|
||||||
|
auto props = acc.Properties(view);
|
||||||
|
if (props.HasError()) {
|
||||||
|
spdlog::debug("Encountered an error while trying to get vertex properties.");
|
||||||
|
return props.GetError();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &properties = props.GetValue();
|
||||||
|
std::transform(properties.begin(), properties.end(), std::inserter(ret, ret.begin()),
|
||||||
|
[](std::pair<const PropertyId, PropertyValue> &pair) {
|
||||||
|
return std::make_pair(pair.first, FromPropertyValueToValue(std::move(pair.second)));
|
||||||
|
});
|
||||||
|
properties.clear();
|
||||||
|
|
||||||
|
auto pks = PrimaryKeysFromAccessor(acc, view, schema);
|
||||||
|
if (pks) {
|
||||||
|
ret.merge(*pks);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
EdgeUniquenessFunction InitializeEdgeUniquenessFunction(bool only_unique_neighbor_rows) {
|
||||||
|
// Functions to select connecting edges based on uniquness
|
||||||
|
EdgeUniquenessFunction maybe_filter_based_on_edge_uniquness;
|
||||||
|
|
||||||
|
if (only_unique_neighbor_rows) {
|
||||||
|
maybe_filter_based_on_edge_uniquness = [](EdgeAccessors &&edges,
|
||||||
|
msgs::EdgeDirection edge_direction) -> EdgeAccessors {
|
||||||
|
std::function<bool(std::set<const storage::v3::VertexId *, VertexIdCmpr> &, const storage::v3::EdgeAccessor &)>
|
||||||
|
is_edge_unique;
|
||||||
|
switch (edge_direction) {
|
||||||
|
case msgs::EdgeDirection::OUT: {
|
||||||
|
is_edge_unique = [](std::set<const storage::v3::VertexId *, VertexIdCmpr> &other_vertex_set,
|
||||||
|
const storage::v3::EdgeAccessor &edge_acc) {
|
||||||
|
auto [it, insertion_happened] = other_vertex_set.insert(&edge_acc.ToVertex());
|
||||||
|
return insertion_happened;
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case msgs::EdgeDirection::IN: {
|
||||||
|
is_edge_unique = [](std::set<const storage::v3::VertexId *, VertexIdCmpr> &other_vertex_set,
|
||||||
|
const storage::v3::EdgeAccessor &edge_acc) {
|
||||||
|
auto [it, insertion_happened] = other_vertex_set.insert(&edge_acc.FromVertex());
|
||||||
|
return insertion_happened;
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case msgs::EdgeDirection::BOTH:
|
||||||
|
MG_ASSERT(false, "This is should never happen, msgs::EdgeDirection::BOTH should not be passed here.");
|
||||||
|
}
|
||||||
|
|
||||||
|
EdgeAccessors ret;
|
||||||
|
std::set<const storage::v3::VertexId *, VertexIdCmpr> other_vertex_set;
|
||||||
|
|
||||||
|
for (const auto &edge : edges) {
|
||||||
|
if (is_edge_unique(other_vertex_set, edge)) {
|
||||||
|
ret.emplace_back(edge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
maybe_filter_based_on_edge_uniquness =
|
||||||
|
[](EdgeAccessors &&edges, msgs::EdgeDirection /*edge_direction*/) -> EdgeAccessors { return std::move(edges); };
|
||||||
|
}
|
||||||
|
|
||||||
|
return maybe_filter_based_on_edge_uniquness;
|
||||||
|
}
|
||||||
|
|
||||||
|
EdgeFiller InitializeEdgeFillerFunction(const msgs::ExpandOneRequest &req) {
|
||||||
|
EdgeFiller edge_filler;
|
||||||
|
|
||||||
|
if (!req.edge_properties) {
|
||||||
|
edge_filler = [transaction_id = req.transaction_id.logical_id](
|
||||||
|
const EdgeAccessor &edge, const bool is_in_edge,
|
||||||
|
msgs::ExpandOneResultRow &result_row) -> ShardResult<void> {
|
||||||
|
auto properties_results = edge.Properties(View::NEW);
|
||||||
|
if (properties_results.HasError()) {
|
||||||
|
spdlog::debug("Encountered an error while trying to get edge properties. Transaction id: {}", transaction_id);
|
||||||
|
return properties_results.GetError();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<PropertyId, msgs::Value> value_properties;
|
||||||
|
for (auto &[prop_key, prop_val] : properties_results.GetValue()) {
|
||||||
|
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)};
|
||||||
|
if (is_in_edge) {
|
||||||
|
result_row.in_edges_with_all_properties.push_back(std::move(edges));
|
||||||
|
} else {
|
||||||
|
result_row.out_edges_with_all_properties.push_back(std::move(edges));
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// TODO(gvolfing) - do we want to set the action_successful here?
|
||||||
|
edge_filler = [&req](const EdgeAccessor &edge, const bool is_in_edge,
|
||||||
|
msgs::ExpandOneResultRow &result_row) -> ShardResult<void> {
|
||||||
|
std::vector<msgs::Value> value_properties;
|
||||||
|
value_properties.reserve(req.edge_properties.value().size());
|
||||||
|
for (const auto &edge_prop : req.edge_properties.value()) {
|
||||||
|
auto property_result = edge.GetProperty(edge_prop, View::NEW);
|
||||||
|
if (property_result.HasError()) {
|
||||||
|
spdlog::debug("Encountered an error while trying to get edge properties. Transaction id: {}",
|
||||||
|
req.transaction_id.logical_id);
|
||||||
|
return property_result.GetError();
|
||||||
|
}
|
||||||
|
value_properties.emplace_back(FromPropertyValueToValue(std::move(property_result.GetValue())));
|
||||||
|
}
|
||||||
|
using EdgeWithSpecificProperties = msgs::ExpandOneResultRow::EdgeWithSpecificProperties;
|
||||||
|
EdgeWithSpecificProperties edges{ToMsgsVertexId(edge.FromVertex()), 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));
|
||||||
|
} else {
|
||||||
|
result_row.out_edges_with_specific_properties.push_back(std::move(edges));
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return edge_filler;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FilterOnVertex(DbAccessor &dba, const storage::v3::VertexAccessor &v_acc, const std::vector<std::string> &filters,
|
||||||
|
const std::string_view node_name) {
|
||||||
|
return std::ranges::all_of(filters, [&node_name, &dba, &v_acc](const auto &filter_expr) {
|
||||||
|
auto res = ComputeExpression(dba, v_acc, std::nullopt, filter_expr, node_name, "");
|
||||||
|
return res.IsBool() && res.ValueBool();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ShardResult<msgs::ExpandOneResultRow> GetExpandOneResult(
|
||||||
|
Shard::Accessor &acc, msgs::VertexId src_vertex, const msgs::ExpandOneRequest &req,
|
||||||
|
const EdgeUniquenessFunction &maybe_filter_based_on_edge_uniqueness, const EdgeFiller &edge_filler,
|
||||||
|
const Schemas::Schema &schema) {
|
||||||
|
/// Fill up source vertex
|
||||||
|
const auto primary_key = ConvertPropertyVector(src_vertex.second);
|
||||||
|
auto v_acc = acc.FindVertex(primary_key, View::NEW);
|
||||||
|
|
||||||
|
msgs::Vertex source_vertex = {.id = src_vertex};
|
||||||
|
auto maybe_secondary_labels = FillUpSourceVertexSecondaryLabels(v_acc, req);
|
||||||
|
if (maybe_secondary_labels.HasError()) {
|
||||||
|
return maybe_secondary_labels.GetError();
|
||||||
|
}
|
||||||
|
source_vertex.labels = std::move(*maybe_secondary_labels);
|
||||||
|
|
||||||
|
auto src_vertex_properties = FillUpSourceVertexProperties(v_acc, req, storage::v3::View::NEW, schema);
|
||||||
|
if (src_vertex_properties.HasError()) {
|
||||||
|
return src_vertex_properties.GetError();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Fill up connecting edges
|
||||||
|
auto fill_up_connecting_edges = FillUpConnectingEdges(v_acc, req, maybe_filter_based_on_edge_uniqueness);
|
||||||
|
if (fill_up_connecting_edges.HasError()) {
|
||||||
|
return fill_up_connecting_edges.GetError();
|
||||||
|
}
|
||||||
|
auto [in_edges, out_edges] = fill_up_connecting_edges.GetValue();
|
||||||
|
|
||||||
|
msgs::ExpandOneResultRow result_row;
|
||||||
|
result_row.src_vertex = std::move(source_vertex);
|
||||||
|
result_row.src_vertex_properties = std::move(*src_vertex_properties);
|
||||||
|
static constexpr bool kInEdges = true;
|
||||||
|
static constexpr bool kOutEdges = false;
|
||||||
|
if (const auto fill_edges_res = FillEdges<kInEdges>(in_edges, result_row, edge_filler); fill_edges_res.HasError()) {
|
||||||
|
return fill_edges_res.GetError();
|
||||||
|
}
|
||||||
|
if (const auto fill_edges_res = FillEdges<kOutEdges>(out_edges, result_row, edge_filler); fill_edges_res.HasError()) {
|
||||||
|
return fill_edges_res.GetError();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result_row;
|
||||||
|
}
|
||||||
|
|
||||||
|
ShardResult<msgs::ExpandOneResultRow> GetExpandOneResult(
|
||||||
|
VertexAccessor v_acc, msgs::VertexId src_vertex, const msgs::ExpandOneRequest &req,
|
||||||
|
std::vector<EdgeAccessor> in_edge_accessors, std::vector<EdgeAccessor> out_edge_accessors,
|
||||||
|
const EdgeUniquenessFunction &maybe_filter_based_on_edge_uniqueness, const EdgeFiller &edge_filler,
|
||||||
|
const Schemas::Schema &schema) {
|
||||||
|
/// Fill up source vertex
|
||||||
|
msgs::Vertex source_vertex = {.id = src_vertex};
|
||||||
|
auto maybe_secondary_labels = FillUpSourceVertexSecondaryLabels(v_acc, req);
|
||||||
|
if (maybe_secondary_labels.HasError()) {
|
||||||
|
return maybe_secondary_labels.GetError();
|
||||||
|
}
|
||||||
|
source_vertex.labels = std::move(*maybe_secondary_labels);
|
||||||
|
|
||||||
|
/// Fill up source vertex properties
|
||||||
|
auto src_vertex_properties = FillUpSourceVertexProperties(v_acc, req, storage::v3::View::NEW, schema);
|
||||||
|
if (src_vertex_properties.HasError()) {
|
||||||
|
return src_vertex_properties.GetError();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Fill up connecting edges
|
||||||
|
auto in_edges = maybe_filter_based_on_edge_uniqueness(std::move(in_edge_accessors), msgs::EdgeDirection::IN);
|
||||||
|
auto out_edges = maybe_filter_based_on_edge_uniqueness(std::move(out_edge_accessors), msgs::EdgeDirection::OUT);
|
||||||
|
|
||||||
|
msgs::ExpandOneResultRow result_row;
|
||||||
|
result_row.src_vertex = std::move(source_vertex);
|
||||||
|
result_row.src_vertex_properties = std::move(*src_vertex_properties);
|
||||||
|
static constexpr bool kInEdges = true;
|
||||||
|
static constexpr bool kOutEdges = false;
|
||||||
|
if (const auto fill_edges_res = FillEdges<kInEdges>(in_edges, result_row, edge_filler); fill_edges_res.HasError()) {
|
||||||
|
return fill_edges_res.GetError();
|
||||||
|
}
|
||||||
|
if (const auto fill_edges_res = FillEdges<kOutEdges>(out_edges, result_row, edge_filler); fill_edges_res.HasError()) {
|
||||||
|
return fill_edges_res.GetError();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result_row;
|
||||||
}
|
}
|
||||||
|
|
||||||
VerticesIterable::Iterator GetStartVertexIterator(VerticesIterable &vertex_iterable,
|
VerticesIterable::Iterator GetStartVertexIterator(VerticesIterable &vertex_iterable,
|
||||||
const std::vector<PropertyValue> &start_ids, const View view) {
|
const std::vector<PropertyValue> &primary_key, const View view) {
|
||||||
auto it = vertex_iterable.begin();
|
auto it = vertex_iterable.begin();
|
||||||
while (it != vertex_iterable.end()) {
|
while (it != vertex_iterable.end()) {
|
||||||
if (const auto &vertex = *it; start_ids <= vertex.PrimaryKey(view).GetValue()) {
|
if (const auto &vertex = *it; primary_key <= vertex.PrimaryKey(view).GetValue()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
++it;
|
++it;
|
||||||
@ -68,15 +450,80 @@ VerticesIterable::Iterator GetStartVertexIterator(VerticesIterable &vertex_itera
|
|||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Element>::const_iterator GetStartOrderedElementsIterator(const std::vector<Element> &ordered_elements,
|
std::vector<Element<VertexAccessor>>::const_iterator GetStartOrderedElementsIterator(
|
||||||
const std::vector<PropertyValue> &start_ids,
|
const std::vector<Element<VertexAccessor>> &ordered_elements, const std::vector<PropertyValue> &primary_key,
|
||||||
const View view) {
|
const View view) {
|
||||||
for (auto it = ordered_elements.begin(); it != ordered_elements.end(); ++it) {
|
for (auto it = ordered_elements.begin(); it != ordered_elements.end(); ++it) {
|
||||||
if (const auto &vertex = it->vertex_acc; start_ids <= vertex.PrimaryKey(view).GetValue()) {
|
if (const auto &vertex = it->object_acc; primary_key <= vertex.PrimaryKey(view).GetValue()) {
|
||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ordered_elements.end();
|
return ordered_elements.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::array<std::vector<EdgeAccessor>, 2> GetEdgesFromVertex(const VertexAccessor &vertex_accessor,
|
||||||
|
const msgs::EdgeDirection direction) {
|
||||||
|
std::vector<EdgeAccessor> in_edges;
|
||||||
|
std::vector<EdgeAccessor> out_edges;
|
||||||
|
|
||||||
|
switch (direction) {
|
||||||
|
case memgraph::msgs::EdgeDirection::IN: {
|
||||||
|
auto edges = vertex_accessor.InEdges(View::OLD);
|
||||||
|
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);
|
||||||
|
auto maybe_out_edges = vertex_accessor.OutEdges(View::OLD);
|
||||||
|
std::vector<EdgeAccessor> edges;
|
||||||
|
if (maybe_in_edges.HasValue()) {
|
||||||
|
in_edges = maybe_in_edges.GetValue();
|
||||||
|
}
|
||||||
|
if (maybe_out_edges.HasValue()) {
|
||||||
|
out_edges = maybe_out_edges.GetValue();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::array<std::vector<EdgeAccessor>, 2>{std::move(in_edges), std::move(out_edges)};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Element<EdgeAccessor>> OrderByEdges(DbAccessor &dba, std::vector<EdgeAccessor> &iterable,
|
||||||
|
std::vector<msgs::OrderBy> &order_by_edges,
|
||||||
|
const VertexAccessor &vertex_acc) {
|
||||||
|
std::vector<Ordering> ordering;
|
||||||
|
ordering.reserve(order_by_edges.size());
|
||||||
|
std::transform(order_by_edges.begin(), order_by_edges.end(), std::back_inserter(ordering),
|
||||||
|
[](const auto &order_by) { return ConvertMsgsOrderByToOrdering(order_by.direction); });
|
||||||
|
|
||||||
|
std::vector<Element<EdgeAccessor>> ordered;
|
||||||
|
for (auto it = iterable.begin(); it != iterable.end(); ++it) {
|
||||||
|
std::vector<TypedValue> properties_order_by;
|
||||||
|
properties_order_by.reserve(order_by_edges.size());
|
||||||
|
std::transform(order_by_edges.begin(), order_by_edges.end(), std::back_inserter(properties_order_by),
|
||||||
|
[&dba, &vertex_acc, &it](const auto &order_by) {
|
||||||
|
return ComputeExpression(dba, vertex_acc, *it, order_by.expression.expression,
|
||||||
|
expr::identifier_node_symbol, expr::identifier_edge_symbol);
|
||||||
|
});
|
||||||
|
|
||||||
|
ordered.push_back({std::move(properties_order_by), *it});
|
||||||
|
}
|
||||||
|
|
||||||
|
auto compare_typed_values = TypedValueVectorCompare(ordering);
|
||||||
|
std::sort(ordered.begin(), ordered.end(), [compare_typed_values](const auto &pair1, const auto &pair2) {
|
||||||
|
return compare_typed_values(pair1.properties_order_by, pair2.properties_order_by);
|
||||||
|
});
|
||||||
|
return ordered;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace memgraph::storage::v3
|
} // namespace memgraph::storage::v3
|
||||||
|
@ -9,14 +9,29 @@
|
|||||||
// by the Apache License, Version 2.0, included in the file
|
// by the Apache License, Version 2.0, included in the file
|
||||||
// licenses/APL.txt.
|
// licenses/APL.txt.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "ast/ast.hpp"
|
#include "query/v2/requests.hpp"
|
||||||
|
#include "storage/v3/bindings/ast/ast.hpp"
|
||||||
|
#include "storage/v3/bindings/pretty_print_ast_to_original_expression.hpp"
|
||||||
#include "storage/v3/bindings/typed_value.hpp"
|
#include "storage/v3/bindings/typed_value.hpp"
|
||||||
|
#include "storage/v3/edge_accessor.hpp"
|
||||||
|
#include "storage/v3/expr.hpp"
|
||||||
#include "storage/v3/shard.hpp"
|
#include "storage/v3/shard.hpp"
|
||||||
#include "storage/v3/vertex_accessor.hpp"
|
#include "storage/v3/vertex_accessor.hpp"
|
||||||
|
#include "utils/template_utils.hpp"
|
||||||
|
|
||||||
namespace memgraph::storage::v3 {
|
namespace memgraph::storage::v3 {
|
||||||
|
using EdgeAccessors = std::vector<storage::v3::EdgeAccessor>;
|
||||||
|
using EdgeUniquenessFunction = std::function<EdgeAccessors(EdgeAccessors &&, msgs::EdgeDirection)>;
|
||||||
|
using EdgeFiller =
|
||||||
|
std::function<ShardResult<void>(const EdgeAccessor &edge, bool is_in_edge, msgs::ExpandOneResultRow &result_row)>;
|
||||||
|
using msgs::Value;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
concept ObjectAccessor = utils::SameAsAnyOf<T, VertexAccessor, EdgeAccessor>;
|
||||||
|
|
||||||
inline bool TypedValueCompare(const TypedValue &a, const TypedValue &b) {
|
inline bool TypedValueCompare(const TypedValue &a, const TypedValue &b) {
|
||||||
// in ordering null comes after everything else
|
// in ordering null comes after everything else
|
||||||
@ -72,6 +87,17 @@ inline bool TypedValueCompare(const TypedValue &a, const TypedValue &b) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline Ordering ConvertMsgsOrderByToOrdering(msgs::OrderingDirection ordering) {
|
||||||
|
switch (ordering) {
|
||||||
|
case memgraph::msgs::OrderingDirection::ASCENDING:
|
||||||
|
return memgraph::storage::v3::Ordering::ASC;
|
||||||
|
case memgraph::msgs::OrderingDirection::DESCENDING:
|
||||||
|
return memgraph::storage::v3::Ordering::DESC;
|
||||||
|
default:
|
||||||
|
LOG_FATAL("Unknown ordering direction");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class TypedValueVectorCompare final {
|
class TypedValueVectorCompare final {
|
||||||
public:
|
public:
|
||||||
explicit TypedValueVectorCompare(const std::vector<Ordering> &ordering) : ordering_(ordering) {}
|
explicit TypedValueVectorCompare(const std::vector<Ordering> &ordering) : ordering_(ordering) {}
|
||||||
@ -99,18 +125,84 @@ class TypedValueVectorCompare final {
|
|||||||
std::vector<Ordering> ordering_;
|
std::vector<Ordering> ordering_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <ObjectAccessor TObjectAccessor>
|
||||||
struct Element {
|
struct Element {
|
||||||
std::vector<TypedValue> properties_order_by;
|
std::vector<TypedValue> properties_order_by;
|
||||||
VertexAccessor vertex_acc;
|
TObjectAccessor object_acc;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<Element> OrderByElements(Shard::Accessor &acc, DbAccessor &dba, VerticesIterable &vertices_iterable,
|
template <typename T>
|
||||||
std::vector<msgs::OrderBy> &order_bys);
|
concept VerticesIt = utils::SameAsAnyOf<T, VerticesIterable, std::vector<VertexAccessor>>;
|
||||||
|
|
||||||
|
template <VerticesIt TIterable>
|
||||||
|
std::vector<Element<VertexAccessor>> OrderByVertices(DbAccessor &dba, TIterable &iterable,
|
||||||
|
std::vector<msgs::OrderBy> &order_by_vertices) {
|
||||||
|
std::vector<Ordering> ordering;
|
||||||
|
ordering.reserve(order_by_vertices.size());
|
||||||
|
std::transform(order_by_vertices.begin(), order_by_vertices.end(), std::back_inserter(ordering),
|
||||||
|
[](const auto &order_by) { return ConvertMsgsOrderByToOrdering(order_by.direction); });
|
||||||
|
|
||||||
|
std::vector<Element<VertexAccessor>> ordered;
|
||||||
|
for (auto it = iterable.begin(); it != iterable.end(); ++it) {
|
||||||
|
std::vector<TypedValue> properties_order_by;
|
||||||
|
properties_order_by.reserve(order_by_vertices.size());
|
||||||
|
|
||||||
|
std::transform(order_by_vertices.begin(), order_by_vertices.end(), std::back_inserter(properties_order_by),
|
||||||
|
[&dba, &it](const auto &order_by) {
|
||||||
|
return ComputeExpression(dba, *it, std::nullopt /*e_acc*/, order_by.expression.expression,
|
||||||
|
expr::identifier_node_symbol, expr::identifier_edge_symbol);
|
||||||
|
});
|
||||||
|
|
||||||
|
ordered.push_back({std::move(properties_order_by), *it});
|
||||||
|
}
|
||||||
|
|
||||||
|
auto compare_typed_values = TypedValueVectorCompare(ordering);
|
||||||
|
std::sort(ordered.begin(), ordered.end(), [compare_typed_values](const auto &pair1, const auto &pair2) {
|
||||||
|
return compare_typed_values(pair1.properties_order_by, pair2.properties_order_by);
|
||||||
|
});
|
||||||
|
return ordered;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Element<EdgeAccessor>> OrderByEdges(DbAccessor &dba, std::vector<EdgeAccessor> &iterable,
|
||||||
|
std::vector<msgs::OrderBy> &order_by_edges,
|
||||||
|
const VertexAccessor &vertex_acc);
|
||||||
|
|
||||||
VerticesIterable::Iterator GetStartVertexIterator(VerticesIterable &vertex_iterable,
|
VerticesIterable::Iterator GetStartVertexIterator(VerticesIterable &vertex_iterable,
|
||||||
const std::vector<PropertyValue> &start_ids, View view);
|
const std::vector<PropertyValue> &primary_key, View view);
|
||||||
|
|
||||||
std::vector<Element>::const_iterator GetStartOrderedElementsIterator(const std::vector<Element> &ordered_elements,
|
std::vector<Element<VertexAccessor>>::const_iterator GetStartOrderedElementsIterator(
|
||||||
const std::vector<PropertyValue> &start_ids,
|
const std::vector<Element<VertexAccessor>> &ordered_elements, const std::vector<PropertyValue> &primary_key,
|
||||||
View view);
|
View view);
|
||||||
|
|
||||||
|
std::array<std::vector<EdgeAccessor>, 2> GetEdgesFromVertex(const VertexAccessor &vertex_accessor,
|
||||||
|
msgs::EdgeDirection direction);
|
||||||
|
|
||||||
|
bool FilterOnVertex(DbAccessor &dba, const storage::v3::VertexAccessor &v_acc, const std::vector<std::string> &filters,
|
||||||
|
std::string_view node_name);
|
||||||
|
|
||||||
|
std::vector<TypedValue> EvaluateVertexExpressions(DbAccessor &dba, const VertexAccessor &v_acc,
|
||||||
|
const std::vector<std::string> &expressions,
|
||||||
|
std::string_view node_name);
|
||||||
|
|
||||||
|
ShardResult<std::map<PropertyId, Value>> CollectSpecificPropertiesFromAccessor(const VertexAccessor &acc,
|
||||||
|
const std::vector<PropertyId> &props,
|
||||||
|
View view);
|
||||||
|
|
||||||
|
ShardResult<std::map<PropertyId, Value>> CollectAllPropertiesFromAccessor(const VertexAccessor &acc, View view,
|
||||||
|
const Schemas::Schema &schema);
|
||||||
|
|
||||||
|
EdgeUniquenessFunction InitializeEdgeUniquenessFunction(bool only_unique_neighbor_rows);
|
||||||
|
|
||||||
|
EdgeFiller InitializeEdgeFillerFunction(const msgs::ExpandOneRequest &req);
|
||||||
|
|
||||||
|
ShardResult<msgs::ExpandOneResultRow> GetExpandOneResult(
|
||||||
|
Shard::Accessor &acc, msgs::VertexId src_vertex, const msgs::ExpandOneRequest &req,
|
||||||
|
const EdgeUniquenessFunction &maybe_filter_based_on_edge_uniqueness, const EdgeFiller &edge_filler,
|
||||||
|
const Schemas::Schema &schema);
|
||||||
|
|
||||||
|
ShardResult<msgs::ExpandOneResultRow> GetExpandOneResult(
|
||||||
|
VertexAccessor v_acc, msgs::VertexId src_vertex, const msgs::ExpandOneRequest &req,
|
||||||
|
std::vector<EdgeAccessor> in_edge_accessors, std::vector<EdgeAccessor> out_edge_accessors,
|
||||||
|
const EdgeUniquenessFunction &maybe_filter_based_on_edge_uniqueness, const EdgeFiller &edge_filler,
|
||||||
|
const Schemas::Schema &schema);
|
||||||
} // namespace memgraph::storage::v3
|
} // namespace memgraph::storage::v3
|
||||||
|
@ -11,24 +11,43 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <experimental/source_location>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include "common/errors.hpp"
|
||||||
#include "utils/result.hpp"
|
#include "utils/result.hpp"
|
||||||
|
|
||||||
namespace memgraph::storage::v3 {
|
namespace memgraph::storage::v3 {
|
||||||
|
|
||||||
static_assert(std::is_same_v<uint8_t, unsigned char>);
|
static_assert(std::is_same_v<uint8_t, unsigned char>);
|
||||||
|
|
||||||
enum class Error : uint8_t {
|
struct ShardError {
|
||||||
SERIALIZATION_ERROR,
|
ShardError(common::ErrorCode code, std::string message, const std::experimental::source_location location)
|
||||||
NONEXISTENT_OBJECT,
|
: code{code}, message{std::move(message)}, source{fmt::format("{}:{}", location.file_name(), location.line())} {}
|
||||||
DELETED_OBJECT,
|
|
||||||
VERTEX_HAS_EDGES,
|
ShardError(common::ErrorCode code, const std::experimental::source_location location)
|
||||||
PROPERTIES_DISABLED,
|
: code{code}, source{fmt::format("{}:{}", location.file_name(), location.line())} {}
|
||||||
VERTEX_ALREADY_INSERTED
|
|
||||||
|
common::ErrorCode code;
|
||||||
|
std::string message;
|
||||||
|
std::string source;
|
||||||
|
|
||||||
|
inline friend bool operator==(const ShardError &lhs, const ShardError &rhs) { return lhs.code == rhs.code; }
|
||||||
|
|
||||||
|
inline friend bool operator==(const ShardError &lhs, const common::ErrorCode rhs) { return lhs.code == rhs; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
||||||
|
#define SHARD_ERROR(error, ...) \
|
||||||
|
({ \
|
||||||
|
using ErrorCode = memgraph::common::ErrorCode; \
|
||||||
|
memgraph::storage::v3::ShardError(error, GET_MESSAGE(__VA_ARGS__), std::experimental::source_location::current()); \
|
||||||
|
})
|
||||||
|
|
||||||
template <class TValue>
|
template <class TValue>
|
||||||
using Result = utils::BasicResult<Error, TValue>;
|
using ShardResult = utils::BasicResult<ShardError, TValue>;
|
||||||
|
|
||||||
} // namespace memgraph::storage::v3
|
} // namespace memgraph::storage::v3
|
||||||
|
@ -16,67 +16,58 @@
|
|||||||
#include <ranges>
|
#include <ranges>
|
||||||
|
|
||||||
#include "common/types.hpp"
|
#include "common/types.hpp"
|
||||||
|
#include "storage/v3/name_id_mapper.hpp"
|
||||||
|
#include "storage/v3/result.hpp"
|
||||||
#include "storage/v3/schemas.hpp"
|
#include "storage/v3/schemas.hpp"
|
||||||
|
|
||||||
namespace memgraph::storage::v3 {
|
namespace memgraph::storage::v3 {
|
||||||
|
|
||||||
bool operator==(const SchemaViolation &lhs, const SchemaViolation &rhs) {
|
SchemaValidator::SchemaValidator(Schemas &schemas, const NameIdMapper &name_id_mapper)
|
||||||
return lhs.status == rhs.status && lhs.label == rhs.label &&
|
: schemas_{&schemas}, name_id_mapper_{&name_id_mapper} {}
|
||||||
lhs.violated_schema_property == rhs.violated_schema_property &&
|
|
||||||
lhs.violated_property_value == rhs.violated_property_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
SchemaViolation::SchemaViolation(ValidationStatus status, LabelId label) : status{status}, label{label} {}
|
ShardResult<void> SchemaValidator::ValidateVertexCreate(LabelId primary_label, const std::vector<LabelId> &labels,
|
||||||
|
|
||||||
SchemaViolation::SchemaViolation(ValidationStatus status, LabelId label, SchemaProperty violated_schema_property)
|
|
||||||
: status{status}, label{label}, violated_schema_property{violated_schema_property} {}
|
|
||||||
|
|
||||||
SchemaViolation::SchemaViolation(ValidationStatus status, LabelId label, SchemaProperty violated_schema_property,
|
|
||||||
PropertyValue violated_property_value)
|
|
||||||
: status{status},
|
|
||||||
label{label},
|
|
||||||
violated_schema_property{violated_schema_property},
|
|
||||||
violated_property_value{violated_property_value} {}
|
|
||||||
|
|
||||||
SchemaValidator::SchemaValidator(Schemas &schemas) : schemas_{schemas} {}
|
|
||||||
|
|
||||||
std::optional<SchemaViolation> SchemaValidator::ValidateVertexCreate(
|
|
||||||
LabelId primary_label, const std::vector<LabelId> &labels,
|
|
||||||
const std::vector<PropertyValue> &primary_properties) const {
|
const std::vector<PropertyValue> &primary_properties) const {
|
||||||
// Schema on primary label
|
// Schema on primary label
|
||||||
const auto *schema = schemas_.GetSchema(primary_label);
|
const auto *schema = schemas_->GetSchema(primary_label);
|
||||||
if (schema == nullptr) {
|
if (schema == nullptr) {
|
||||||
return SchemaViolation(SchemaViolation::ValidationStatus::NO_SCHEMA_DEFINED_FOR_LABEL, primary_label);
|
return SHARD_ERROR(ErrorCode::SCHEMA_NO_SCHEMA_DEFINED_FOR_LABEL, "Schema not defined for label :{}",
|
||||||
|
name_id_mapper_->IdToName(primary_label.AsInt()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Is there another primary label among secondary labels
|
// Is there another primary label among secondary labels
|
||||||
for (const auto &secondary_label : labels) {
|
for (const auto &secondary_label : labels) {
|
||||||
if (schemas_.GetSchema(secondary_label)) {
|
if (schemas_->GetSchema(secondary_label)) {
|
||||||
return SchemaViolation(SchemaViolation::ValidationStatus::VERTEX_SECONDARY_LABEL_IS_PRIMARY, secondary_label);
|
return SHARD_ERROR(ErrorCode::SCHEMA_VERTEX_SECONDARY_LABEL_IS_PRIMARY,
|
||||||
|
"Cannot add label :{}, since it is defined as a primary label",
|
||||||
|
name_id_mapper_->IdToName(secondary_label.AsInt()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Quick size check
|
// Quick size check
|
||||||
if (schema->second.size() != primary_properties.size()) {
|
if (schema->second.size() != primary_properties.size()) {
|
||||||
return SchemaViolation(SchemaViolation::ValidationStatus::VERTEX_PRIMARY_PROPERTIES_UNDEFINED, primary_label);
|
return SHARD_ERROR(ErrorCode::SCHEMA_VERTEX_PRIMARY_PROPERTIES_UNDEFINED,
|
||||||
|
"Not all primary properties have been specified for :{} vertex",
|
||||||
|
name_id_mapper_->IdToName(primary_label.AsInt()));
|
||||||
}
|
}
|
||||||
// Check only properties defined by schema
|
// Check only properties defined by schema
|
||||||
for (size_t i{0}; i < schema->second.size(); ++i) {
|
for (size_t i{0}; i < schema->second.size(); ++i) {
|
||||||
// Check schema property type
|
// Check schema property type
|
||||||
if (auto property_schema_type = PropertyTypeToSchemaType(primary_properties[i]);
|
if (auto property_schema_type = PropertyTypeToSchemaType(primary_properties[i]);
|
||||||
property_schema_type && *property_schema_type != schema->second[i].type) {
|
property_schema_type && *property_schema_type != schema->second[i].type) {
|
||||||
return SchemaViolation(SchemaViolation::ValidationStatus::VERTEX_PROPERTY_WRONG_TYPE, primary_label,
|
return SHARD_ERROR(ErrorCode::SCHEMA_VERTEX_PROPERTY_WRONG_TYPE,
|
||||||
schema->second[i], primary_properties[i]);
|
"Property {} is of wrong type, expected {}, actual {}",
|
||||||
|
name_id_mapper_->IdToName(schema->second[i].property_id.AsInt()),
|
||||||
|
SchemaTypeToString(schema->second[i].type), SchemaTypeToString(*property_schema_type));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::nullopt;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<SchemaViolation> SchemaValidator::ValidatePropertyUpdate(const LabelId primary_label,
|
ShardResult<void> SchemaValidator::ValidatePropertyUpdate(const LabelId primary_label,
|
||||||
const PropertyId property_id) const {
|
const PropertyId property_id) const {
|
||||||
// Verify existence of schema on primary label
|
// Verify existence of schema on primary label
|
||||||
const auto *schema = schemas_.GetSchema(primary_label);
|
const auto *schema = schemas_->GetSchema(primary_label);
|
||||||
MG_ASSERT(schema, "Cannot validate against non existing schema!");
|
MG_ASSERT(schema, "Cannot validate against non existing schema!");
|
||||||
|
|
||||||
// Verify that updating property is not part of schema
|
// Verify that updating property is not part of schema
|
||||||
@ -84,34 +75,37 @@ std::optional<SchemaViolation> SchemaValidator::ValidatePropertyUpdate(const Lab
|
|||||||
schema->second,
|
schema->second,
|
||||||
[property_id](const auto &schema_property) { return property_id == schema_property.property_id; });
|
[property_id](const auto &schema_property) { return property_id == schema_property.property_id; });
|
||||||
schema_property != schema->second.end()) {
|
schema_property != schema->second.end()) {
|
||||||
return SchemaViolation(SchemaViolation::ValidationStatus::VERTEX_UPDATE_PRIMARY_KEY, primary_label,
|
return SHARD_ERROR(ErrorCode::SCHEMA_VERTEX_UPDATE_PRIMARY_KEY,
|
||||||
*schema_property);
|
"Cannot update primary property {} of schema on label :{}",
|
||||||
|
name_id_mapper_->IdToName(schema_property->property_id.AsInt()),
|
||||||
|
name_id_mapper_->IdToName(primary_label.AsInt()));
|
||||||
}
|
}
|
||||||
return std::nullopt;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<SchemaViolation> SchemaValidator::ValidateLabelUpdate(const LabelId label) const {
|
ShardResult<void> SchemaValidator::ValidateLabelUpdate(const LabelId label) const {
|
||||||
const auto *schema = schemas_.GetSchema(label);
|
const auto *schema = schemas_->GetSchema(label);
|
||||||
if (schema) {
|
if (schema) {
|
||||||
return SchemaViolation(SchemaViolation::ValidationStatus::VERTEX_UPDATE_PRIMARY_LABEL, label);
|
return SHARD_ERROR(ErrorCode::SCHEMA_VERTEX_UPDATE_PRIMARY_LABEL, "Cannot add/remove primary label :{}",
|
||||||
|
name_id_mapper_->IdToName(label.AsInt()));
|
||||||
}
|
}
|
||||||
return std::nullopt;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const Schemas::Schema *SchemaValidator::GetSchema(LabelId label) const { return schemas_.GetSchema(label); }
|
const Schemas::Schema *SchemaValidator::GetSchema(LabelId label) const { return schemas_->GetSchema(label); }
|
||||||
|
|
||||||
VertexValidator::VertexValidator(const SchemaValidator &schema_validator, const LabelId primary_label)
|
VertexValidator::VertexValidator(const SchemaValidator &schema_validator, const LabelId primary_label)
|
||||||
: schema_validator{&schema_validator}, primary_label_{primary_label} {}
|
: schema_validator{&schema_validator}, primary_label_{primary_label} {}
|
||||||
|
|
||||||
std::optional<SchemaViolation> VertexValidator::ValidatePropertyUpdate(PropertyId property_id) const {
|
ShardResult<void> VertexValidator::ValidatePropertyUpdate(PropertyId property_id) const {
|
||||||
return schema_validator->ValidatePropertyUpdate(primary_label_, property_id);
|
return schema_validator->ValidatePropertyUpdate(primary_label_, property_id);
|
||||||
};
|
};
|
||||||
|
|
||||||
std::optional<SchemaViolation> VertexValidator::ValidateAddLabel(LabelId label) const {
|
ShardResult<void> VertexValidator::ValidateAddLabel(LabelId label) const {
|
||||||
return schema_validator->ValidateLabelUpdate(label);
|
return schema_validator->ValidateLabelUpdate(label);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<SchemaViolation> VertexValidator::ValidateRemoveLabel(LabelId label) const {
|
ShardResult<void> VertexValidator::ValidateRemoveLabel(LabelId label) const {
|
||||||
return schema_validator->ValidateLabelUpdate(label);
|
return schema_validator->ValidateLabelUpdate(label);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,68 +11,43 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <optional>
|
|
||||||
#include <variant>
|
#include <variant>
|
||||||
|
|
||||||
|
#include "storage/v2/result.hpp"
|
||||||
#include "storage/v3/id_types.hpp"
|
#include "storage/v3/id_types.hpp"
|
||||||
|
#include "storage/v3/name_id_mapper.hpp"
|
||||||
#include "storage/v3/property_value.hpp"
|
#include "storage/v3/property_value.hpp"
|
||||||
#include "storage/v3/result.hpp"
|
#include "storage/v3/result.hpp"
|
||||||
#include "storage/v3/schemas.hpp"
|
#include "storage/v3/schemas.hpp"
|
||||||
|
|
||||||
namespace memgraph::storage::v3 {
|
namespace memgraph::storage::v3 {
|
||||||
|
|
||||||
struct SchemaViolation {
|
|
||||||
enum class ValidationStatus : uint8_t {
|
|
||||||
NO_SCHEMA_DEFINED_FOR_LABEL,
|
|
||||||
VERTEX_PROPERTY_WRONG_TYPE,
|
|
||||||
VERTEX_UPDATE_PRIMARY_KEY,
|
|
||||||
VERTEX_UPDATE_PRIMARY_LABEL,
|
|
||||||
VERTEX_SECONDARY_LABEL_IS_PRIMARY,
|
|
||||||
VERTEX_PRIMARY_PROPERTIES_UNDEFINED,
|
|
||||||
};
|
|
||||||
|
|
||||||
SchemaViolation(ValidationStatus status, LabelId label);
|
|
||||||
|
|
||||||
SchemaViolation(ValidationStatus status, LabelId label, SchemaProperty violated_schema_property);
|
|
||||||
|
|
||||||
SchemaViolation(ValidationStatus status, LabelId label, SchemaProperty violated_schema_property,
|
|
||||||
PropertyValue violated_property_value);
|
|
||||||
|
|
||||||
friend bool operator==(const SchemaViolation &lhs, const SchemaViolation &rhs);
|
|
||||||
|
|
||||||
ValidationStatus status;
|
|
||||||
LabelId label;
|
|
||||||
std::optional<SchemaProperty> violated_schema_property;
|
|
||||||
std::optional<PropertyValue> violated_property_value;
|
|
||||||
};
|
|
||||||
|
|
||||||
class SchemaValidator {
|
class SchemaValidator {
|
||||||
public:
|
public:
|
||||||
explicit SchemaValidator(Schemas &schemas);
|
explicit SchemaValidator(Schemas &schemas, const NameIdMapper &name_id_mapper);
|
||||||
|
|
||||||
[[nodiscard]] std::optional<SchemaViolation> ValidateVertexCreate(
|
[[nodiscard]] ShardResult<void> ValidateVertexCreate(LabelId primary_label, const std::vector<LabelId> &labels,
|
||||||
LabelId primary_label, const std::vector<LabelId> &labels,
|
|
||||||
const std::vector<PropertyValue> &primary_properties) const;
|
const std::vector<PropertyValue> &primary_properties) const;
|
||||||
|
|
||||||
[[nodiscard]] std::optional<SchemaViolation> ValidatePropertyUpdate(LabelId primary_label,
|
[[nodiscard]] ShardResult<void> ValidatePropertyUpdate(LabelId primary_label, PropertyId property_id) const;
|
||||||
PropertyId property_id) const;
|
|
||||||
|
|
||||||
[[nodiscard]] std::optional<SchemaViolation> ValidateLabelUpdate(LabelId label) const;
|
[[nodiscard]] ShardResult<void> ValidateLabelUpdate(LabelId label) const;
|
||||||
|
|
||||||
const Schemas::Schema *GetSchema(LabelId label) const;
|
const Schemas::Schema *GetSchema(LabelId label) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Schemas &schemas_;
|
Schemas *schemas_;
|
||||||
|
const NameIdMapper *name_id_mapper_;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct VertexValidator {
|
struct VertexValidator {
|
||||||
explicit VertexValidator(const SchemaValidator &schema_validator, LabelId primary_label);
|
explicit VertexValidator(const SchemaValidator &schema_validator, LabelId primary_label);
|
||||||
|
|
||||||
[[nodiscard]] std::optional<SchemaViolation> ValidatePropertyUpdate(PropertyId property_id) const;
|
[[nodiscard]] ShardResult<void> ValidatePropertyUpdate(PropertyId property_id) const;
|
||||||
|
|
||||||
[[nodiscard]] std::optional<SchemaViolation> ValidateAddLabel(LabelId label) const;
|
[[nodiscard]] ShardResult<void> ValidateAddLabel(LabelId label) const;
|
||||||
|
|
||||||
[[nodiscard]] std::optional<SchemaViolation> ValidateRemoveLabel(LabelId label) const;
|
[[nodiscard]] ShardResult<void> ValidateRemoveLabel(LabelId label) const;
|
||||||
|
|
||||||
const SchemaValidator *schema_validator;
|
const SchemaValidator *schema_validator;
|
||||||
|
|
||||||
|
@ -31,9 +31,10 @@
|
|||||||
#include "storage/v3/indices.hpp"
|
#include "storage/v3/indices.hpp"
|
||||||
#include "storage/v3/key_store.hpp"
|
#include "storage/v3/key_store.hpp"
|
||||||
#include "storage/v3/mvcc.hpp"
|
#include "storage/v3/mvcc.hpp"
|
||||||
|
#include "storage/v3/name_id_mapper.hpp"
|
||||||
#include "storage/v3/property_value.hpp"
|
#include "storage/v3/property_value.hpp"
|
||||||
|
#include "storage/v3/result.hpp"
|
||||||
#include "storage/v3/schema_validator.hpp"
|
#include "storage/v3/schema_validator.hpp"
|
||||||
#include "storage/v3/shard_operation_result.hpp"
|
|
||||||
#include "storage/v3/transaction.hpp"
|
#include "storage/v3/transaction.hpp"
|
||||||
#include "storage/v3/vertex.hpp"
|
#include "storage/v3/vertex.hpp"
|
||||||
#include "storage/v3/vertex_accessor.hpp"
|
#include "storage/v3/vertex_accessor.hpp"
|
||||||
@ -327,7 +328,7 @@ Shard::Shard(const LabelId primary_label, const PrimaryKey min_primary_key,
|
|||||||
: primary_label_{primary_label},
|
: primary_label_{primary_label},
|
||||||
min_primary_key_{min_primary_key},
|
min_primary_key_{min_primary_key},
|
||||||
max_primary_key_{max_primary_key},
|
max_primary_key_{max_primary_key},
|
||||||
schema_validator_{schemas_},
|
schema_validator_{schemas_, name_id_mapper_},
|
||||||
vertex_validator_{schema_validator_, primary_label},
|
vertex_validator_{schema_validator_, primary_label},
|
||||||
indices_{config.items, vertex_validator_},
|
indices_{config.items, vertex_validator_},
|
||||||
isolation_level_{config.transaction.isolation_level},
|
isolation_level_{config.transaction.isolation_level},
|
||||||
@ -344,7 +345,7 @@ Shard::~Shard() {}
|
|||||||
Shard::Accessor::Accessor(Shard &shard, Transaction &transaction)
|
Shard::Accessor::Accessor(Shard &shard, Transaction &transaction)
|
||||||
: shard_(&shard), transaction_(&transaction), config_(shard_->config_.items) {}
|
: shard_(&shard), transaction_(&transaction), config_(shard_->config_.items) {}
|
||||||
|
|
||||||
ShardOperationResult<VertexAccessor> Shard::Accessor::CreateVertexAndValidate(
|
ShardResult<VertexAccessor> Shard::Accessor::CreateVertexAndValidate(
|
||||||
const std::vector<LabelId> &labels, const std::vector<PropertyValue> &primary_properties,
|
const std::vector<LabelId> &labels, const std::vector<PropertyValue> &primary_properties,
|
||||||
const std::vector<std::pair<PropertyId, PropertyValue>> &properties) {
|
const std::vector<std::pair<PropertyId, PropertyValue>> &properties) {
|
||||||
OOMExceptionEnabler oom_exception;
|
OOMExceptionEnabler oom_exception;
|
||||||
@ -352,8 +353,8 @@ ShardOperationResult<VertexAccessor> Shard::Accessor::CreateVertexAndValidate(
|
|||||||
|
|
||||||
auto maybe_schema_violation =
|
auto maybe_schema_violation =
|
||||||
GetSchemaValidator().ValidateVertexCreate(shard_->primary_label_, labels, primary_properties);
|
GetSchemaValidator().ValidateVertexCreate(shard_->primary_label_, labels, primary_properties);
|
||||||
if (maybe_schema_violation) {
|
if (maybe_schema_violation.HasError()) {
|
||||||
return {std::move(*maybe_schema_violation)};
|
return {std::move(maybe_schema_violation.GetError())};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto acc = shard_->vertices_.access();
|
auto acc = shard_->vertices_.access();
|
||||||
@ -363,7 +364,7 @@ ShardOperationResult<VertexAccessor> Shard::Accessor::CreateVertexAndValidate(
|
|||||||
|
|
||||||
VertexAccessor vertex_acc{&it->vertex, transaction_, &shard_->indices_, config_, shard_->vertex_validator_};
|
VertexAccessor vertex_acc{&it->vertex, transaction_, &shard_->indices_, config_, shard_->vertex_validator_};
|
||||||
if (!inserted) {
|
if (!inserted) {
|
||||||
return {Error::VERTEX_ALREADY_INSERTED};
|
return SHARD_ERROR(ErrorCode::VERTEX_ALREADY_INSERTED);
|
||||||
}
|
}
|
||||||
MG_ASSERT(it != acc.end(), "Invalid Vertex accessor!");
|
MG_ASSERT(it != acc.end(), "Invalid Vertex accessor!");
|
||||||
|
|
||||||
@ -394,19 +395,19 @@ std::optional<VertexAccessor> Shard::Accessor::FindVertex(std::vector<PropertyVa
|
|||||||
return VertexAccessor::Create(&it->vertex, transaction_, &shard_->indices_, config_, shard_->vertex_validator_, view);
|
return VertexAccessor::Create(&it->vertex, transaction_, &shard_->indices_, config_, shard_->vertex_validator_, view);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<std::optional<VertexAccessor>> Shard::Accessor::DeleteVertex(VertexAccessor *vertex) {
|
ShardResult<std::optional<VertexAccessor>> Shard::Accessor::DeleteVertex(VertexAccessor *vertex) {
|
||||||
MG_ASSERT(vertex->transaction_ == transaction_,
|
MG_ASSERT(vertex->transaction_ == transaction_,
|
||||||
"VertexAccessor must be from the same transaction as the storage "
|
"VertexAccessor must be from the same transaction as the storage "
|
||||||
"accessor when deleting a vertex!");
|
"accessor when deleting a vertex!");
|
||||||
auto *vertex_ptr = vertex->vertex_;
|
auto *vertex_ptr = vertex->vertex_;
|
||||||
|
|
||||||
if (!PrepareForWrite(transaction_, vertex_ptr)) return Error::SERIALIZATION_ERROR;
|
if (!PrepareForWrite(transaction_, vertex_ptr)) return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR);
|
||||||
|
|
||||||
if (vertex_ptr->deleted) {
|
if (vertex_ptr->deleted) {
|
||||||
return std::optional<VertexAccessor>{};
|
return std::optional<VertexAccessor>{};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!vertex_ptr->in_edges.empty() || !vertex_ptr->out_edges.empty()) return Error::VERTEX_HAS_EDGES;
|
if (!vertex_ptr->in_edges.empty() || !vertex_ptr->out_edges.empty()) return SHARD_ERROR(ErrorCode::VERTEX_HAS_EDGES);
|
||||||
|
|
||||||
CreateAndLinkDelta(transaction_, vertex_ptr, Delta::RecreateObjectTag());
|
CreateAndLinkDelta(transaction_, vertex_ptr, Delta::RecreateObjectTag());
|
||||||
vertex_ptr->deleted = true;
|
vertex_ptr->deleted = true;
|
||||||
@ -415,7 +416,7 @@ Result<std::optional<VertexAccessor>> Shard::Accessor::DeleteVertex(VertexAccess
|
|||||||
shard_->vertex_validator_, true);
|
shard_->vertex_validator_, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<std::optional<std::pair<VertexAccessor, std::vector<EdgeAccessor>>>> Shard::Accessor::DetachDeleteVertex(
|
ShardResult<std::optional<std::pair<VertexAccessor, std::vector<EdgeAccessor>>>> Shard::Accessor::DetachDeleteVertex(
|
||||||
VertexAccessor *vertex) {
|
VertexAccessor *vertex) {
|
||||||
using ReturnType = std::pair<VertexAccessor, std::vector<EdgeAccessor>>;
|
using ReturnType = std::pair<VertexAccessor, std::vector<EdgeAccessor>>;
|
||||||
|
|
||||||
@ -428,7 +429,7 @@ Result<std::optional<std::pair<VertexAccessor, std::vector<EdgeAccessor>>>> Shar
|
|||||||
std::vector<Vertex::EdgeLink> out_edges;
|
std::vector<Vertex::EdgeLink> out_edges;
|
||||||
|
|
||||||
{
|
{
|
||||||
if (!PrepareForWrite(transaction_, vertex_ptr)) return Error::SERIALIZATION_ERROR;
|
if (!PrepareForWrite(transaction_, vertex_ptr)) return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR);
|
||||||
|
|
||||||
if (vertex_ptr->deleted) return std::optional<ReturnType>{};
|
if (vertex_ptr->deleted) return std::optional<ReturnType>{};
|
||||||
|
|
||||||
@ -443,7 +444,7 @@ Result<std::optional<std::pair<VertexAccessor, std::vector<EdgeAccessor>>>> Shar
|
|||||||
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.From(), e.To(), e.Gid());
|
auto ret = DeleteEdge(e.From(), e.To(), e.Gid());
|
||||||
if (ret.HasError()) {
|
if (ret.HasError()) {
|
||||||
MG_ASSERT(ret.GetError() == Error::SERIALIZATION_ERROR, "Invalid database state!");
|
MG_ASSERT(ret.GetError() == common::ErrorCode::SERIALIZATION_ERROR, "Invalid database state!");
|
||||||
return ret.GetError();
|
return ret.GetError();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -456,7 +457,7 @@ Result<std::optional<std::pair<VertexAccessor, std::vector<EdgeAccessor>>>> Shar
|
|||||||
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.From(), e.To(), e.Gid());
|
auto ret = DeleteEdge(e.From(), e.To(), e.Gid());
|
||||||
if (ret.HasError()) {
|
if (ret.HasError()) {
|
||||||
MG_ASSERT(ret.GetError() == Error::SERIALIZATION_ERROR, "Invalid database state!");
|
MG_ASSERT(ret.GetError() == common::ErrorCode::SERIALIZATION_ERROR, "Invalid database state!");
|
||||||
return ret.GetError();
|
return ret.GetError();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -469,7 +470,7 @@ Result<std::optional<std::pair<VertexAccessor, std::vector<EdgeAccessor>>>> Shar
|
|||||||
// vertex. Some other transaction could have modified the vertex in the
|
// vertex. Some other transaction could have modified the vertex in the
|
||||||
// meantime if we didn't have any edges to delete.
|
// meantime if we didn't have any edges to delete.
|
||||||
|
|
||||||
if (!PrepareForWrite(transaction_, vertex_ptr)) return Error::SERIALIZATION_ERROR;
|
if (!PrepareForWrite(transaction_, vertex_ptr)) return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR);
|
||||||
|
|
||||||
MG_ASSERT(!vertex_ptr->deleted, "Invalid database state!");
|
MG_ASSERT(!vertex_ptr->deleted, "Invalid database state!");
|
||||||
|
|
||||||
@ -481,7 +482,7 @@ Result<std::optional<std::pair<VertexAccessor, std::vector<EdgeAccessor>>>> Shar
|
|||||||
std::move(deleted_edges));
|
std::move(deleted_edges));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<EdgeAccessor> Shard::Accessor::CreateEdge(VertexId from_vertex_id, VertexId to_vertex_id,
|
ShardResult<EdgeAccessor> Shard::Accessor::CreateEdge(VertexId from_vertex_id, VertexId to_vertex_id,
|
||||||
const EdgeTypeId edge_type, const Gid gid) {
|
const EdgeTypeId edge_type, const Gid gid) {
|
||||||
OOMExceptionEnabler oom_exception;
|
OOMExceptionEnabler oom_exception;
|
||||||
Vertex *from_vertex{nullptr};
|
Vertex *from_vertex{nullptr};
|
||||||
@ -506,12 +507,12 @@ Result<EdgeAccessor> Shard::Accessor::CreateEdge(VertexId from_vertex_id, Vertex
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (from_is_local) {
|
if (from_is_local) {
|
||||||
if (!PrepareForWrite(transaction_, from_vertex)) return Error::SERIALIZATION_ERROR;
|
if (!PrepareForWrite(transaction_, from_vertex)) return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR);
|
||||||
if (from_vertex->deleted) return Error::DELETED_OBJECT;
|
if (from_vertex->deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
|
||||||
}
|
}
|
||||||
if (to_is_local && to_vertex != from_vertex) {
|
if (to_is_local && to_vertex != from_vertex) {
|
||||||
if (!PrepareForWrite(transaction_, to_vertex)) return Error::SERIALIZATION_ERROR;
|
if (!PrepareForWrite(transaction_, to_vertex)) return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR);
|
||||||
if (to_vertex->deleted) return Error::DELETED_OBJECT;
|
if (to_vertex->deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
|
||||||
}
|
}
|
||||||
|
|
||||||
EdgeRef edge(gid);
|
EdgeRef edge(gid);
|
||||||
@ -540,7 +541,7 @@ Result<EdgeAccessor> Shard::Accessor::CreateEdge(VertexId from_vertex_id, Vertex
|
|||||||
&shard_->indices_, config_);
|
&shard_->indices_, config_);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<std::optional<EdgeAccessor>> Shard::Accessor::DeleteEdge(VertexId from_vertex_id, VertexId to_vertex_id,
|
ShardResult<std::optional<EdgeAccessor>> Shard::Accessor::DeleteEdge(VertexId from_vertex_id, VertexId to_vertex_id,
|
||||||
const Gid edge_id) {
|
const Gid edge_id) {
|
||||||
Vertex *from_vertex{nullptr};
|
Vertex *from_vertex{nullptr};
|
||||||
Vertex *to_vertex{nullptr};
|
Vertex *to_vertex{nullptr};
|
||||||
@ -566,13 +567,13 @@ Result<std::optional<EdgeAccessor>> Shard::Accessor::DeleteEdge(VertexId from_ve
|
|||||||
|
|
||||||
if (from_is_local) {
|
if (from_is_local) {
|
||||||
if (!PrepareForWrite(transaction_, from_vertex)) {
|
if (!PrepareForWrite(transaction_, from_vertex)) {
|
||||||
return Error::SERIALIZATION_ERROR;
|
return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR);
|
||||||
}
|
}
|
||||||
MG_ASSERT(!from_vertex->deleted, "Invalid database state!");
|
MG_ASSERT(!from_vertex->deleted, "Invalid database state!");
|
||||||
}
|
}
|
||||||
if (to_is_local && to_vertex != from_vertex) {
|
if (to_is_local && to_vertex != from_vertex) {
|
||||||
if (!PrepareForWrite(transaction_, to_vertex)) {
|
if (!PrepareForWrite(transaction_, to_vertex)) {
|
||||||
return Error::SERIALIZATION_ERROR;
|
return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR);
|
||||||
}
|
}
|
||||||
MG_ASSERT(!to_vertex->deleted, "Invalid database state!");
|
MG_ASSERT(!to_vertex->deleted, "Invalid database state!");
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,6 @@
|
|||||||
#include "storage/v3/result.hpp"
|
#include "storage/v3/result.hpp"
|
||||||
#include "storage/v3/schema_validator.hpp"
|
#include "storage/v3/schema_validator.hpp"
|
||||||
#include "storage/v3/schemas.hpp"
|
#include "storage/v3/schemas.hpp"
|
||||||
#include "storage/v3/shard_operation_result.hpp"
|
|
||||||
#include "storage/v3/transaction.hpp"
|
#include "storage/v3/transaction.hpp"
|
||||||
#include "storage/v3/vertex.hpp"
|
#include "storage/v3/vertex.hpp"
|
||||||
#include "storage/v3/vertex_accessor.hpp"
|
#include "storage/v3/vertex_accessor.hpp"
|
||||||
@ -207,7 +206,7 @@ class Shard final {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
/// @throw std::bad_alloc
|
/// @throw std::bad_alloc
|
||||||
ShardOperationResult<VertexAccessor> CreateVertexAndValidate(
|
ShardResult<VertexAccessor> CreateVertexAndValidate(
|
||||||
const std::vector<LabelId> &labels, const std::vector<PropertyValue> &primary_properties,
|
const std::vector<LabelId> &labels, const std::vector<PropertyValue> &primary_properties,
|
||||||
const std::vector<std::pair<PropertyId, PropertyValue>> &properties);
|
const std::vector<std::pair<PropertyId, PropertyValue>> &properties);
|
||||||
|
|
||||||
@ -262,19 +261,19 @@ class Shard final {
|
|||||||
|
|
||||||
/// @return Accessor to the deleted vertex if a deletion took place, std::nullopt otherwise
|
/// @return Accessor to the deleted vertex if a deletion took place, std::nullopt otherwise
|
||||||
/// @throw std::bad_alloc
|
/// @throw std::bad_alloc
|
||||||
Result<std::optional<VertexAccessor>> DeleteVertex(VertexAccessor *vertex);
|
ShardResult<std::optional<VertexAccessor>> DeleteVertex(VertexAccessor *vertex);
|
||||||
|
|
||||||
/// @return Accessor to the deleted vertex and deleted edges if a deletion took place, std::nullopt otherwise
|
/// @return Accessor to the deleted vertex and deleted edges if a deletion took place, std::nullopt otherwise
|
||||||
/// @throw std::bad_alloc
|
/// @throw std::bad_alloc
|
||||||
Result<std::optional<std::pair<VertexAccessor, std::vector<EdgeAccessor>>>> DetachDeleteVertex(
|
ShardResult<std::optional<std::pair<VertexAccessor, std::vector<EdgeAccessor>>>> DetachDeleteVertex(
|
||||||
VertexAccessor *vertex);
|
VertexAccessor *vertex);
|
||||||
|
|
||||||
/// @throw std::bad_alloc
|
/// @throw std::bad_alloc
|
||||||
Result<EdgeAccessor> CreateEdge(VertexId from_vertex_id, VertexId to_vertex_id, EdgeTypeId edge_type, Gid gid);
|
ShardResult<EdgeAccessor> CreateEdge(VertexId from_vertex_id, VertexId to_vertex_id, EdgeTypeId edge_type, Gid gid);
|
||||||
|
|
||||||
/// Accessor to the deleted edge if a deletion took place, std::nullopt otherwise
|
/// Accessor to the deleted edge if a deletion took place, std::nullopt otherwise
|
||||||
/// @throw std::bad_alloc
|
/// @throw std::bad_alloc
|
||||||
Result<std::optional<EdgeAccessor>> DeleteEdge(VertexId from_vertex_id, VertexId to_vertex_id, Gid edge_id);
|
ShardResult<std::optional<EdgeAccessor>> DeleteEdge(VertexId from_vertex_id, VertexId to_vertex_id, Gid edge_id);
|
||||||
|
|
||||||
LabelId NameToLabel(std::string_view name) const;
|
LabelId NameToLabel(std::string_view name) const;
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
#include "storage/v3/key_store.hpp"
|
#include "storage/v3/key_store.hpp"
|
||||||
#include "storage/v3/property_value.hpp"
|
#include "storage/v3/property_value.hpp"
|
||||||
#include "storage/v3/request_helper.hpp"
|
#include "storage/v3/request_helper.hpp"
|
||||||
|
#include "storage/v3/result.hpp"
|
||||||
#include "storage/v3/schemas.hpp"
|
#include "storage/v3/schemas.hpp"
|
||||||
#include "storage/v3/shard.hpp"
|
#include "storage/v3/shard.hpp"
|
||||||
#include "storage/v3/shard_rsm.hpp"
|
#include "storage/v3/shard_rsm.hpp"
|
||||||
@ -41,443 +42,38 @@
|
|||||||
#include "storage/v3/vertex_accessor.hpp"
|
#include "storage/v3/vertex_accessor.hpp"
|
||||||
#include "storage/v3/vertex_id.hpp"
|
#include "storage/v3/vertex_id.hpp"
|
||||||
#include "storage/v3/view.hpp"
|
#include "storage/v3/view.hpp"
|
||||||
|
#include "utils/logging.hpp"
|
||||||
|
|
||||||
namespace memgraph::storage::v3 {
|
namespace memgraph::storage::v3 {
|
||||||
using msgs::Label;
|
using msgs::Label;
|
||||||
using msgs::PropertyId;
|
using msgs::PropertyId;
|
||||||
using msgs::Value;
|
using msgs::Value;
|
||||||
|
|
||||||
|
using conversions::ConvertPropertyMap;
|
||||||
using conversions::ConvertPropertyVector;
|
using conversions::ConvertPropertyVector;
|
||||||
using conversions::ConvertValueVector;
|
using conversions::ConvertValueVector;
|
||||||
|
using conversions::FromMap;
|
||||||
using conversions::FromPropertyValueToValue;
|
using conversions::FromPropertyValueToValue;
|
||||||
using conversions::ToMsgsVertexId;
|
using conversions::ToMsgsVertexId;
|
||||||
using conversions::ToPropertyValue;
|
using conversions::ToPropertyValue;
|
||||||
|
|
||||||
namespace {
|
auto CreateErrorResponse(const ShardError &shard_error, const auto transaction_id, const std::string_view action) {
|
||||||
namespace msgs = msgs;
|
msgs::ShardError message_shard_error{shard_error.code, shard_error.message};
|
||||||
|
spdlog::debug("{} In transaction {} {} failed: {}: {}", shard_error.source, transaction_id.logical_id, action,
|
||||||
using AllEdgePropertyDataSructure = std::map<PropertyId, msgs::Value>;
|
ErrorCodeToString(shard_error.code), shard_error.message);
|
||||||
using SpecificEdgePropertyDataSructure = std::vector<msgs::Value>;
|
return message_shard_error;
|
||||||
|
|
||||||
using AllEdgeProperties = std::tuple<msgs::VertexId, msgs::Gid, AllEdgePropertyDataSructure>;
|
|
||||||
using SpecificEdgeProperties = std::tuple<msgs::VertexId, msgs::Gid, SpecificEdgePropertyDataSructure>;
|
|
||||||
|
|
||||||
using SpecificEdgePropertiesVector = std::vector<SpecificEdgeProperties>;
|
|
||||||
using AllEdgePropertiesVector = std::vector<AllEdgeProperties>;
|
|
||||||
|
|
||||||
using EdgeAccessors = std::vector<storage::v3::EdgeAccessor>;
|
|
||||||
|
|
||||||
using EdgeFiller = std::function<bool(const EdgeAccessor &edge, bool is_in_edge, msgs::ExpandOneResultRow &result_row)>;
|
|
||||||
using EdgeUniqunessFunction = std::function<EdgeAccessors(EdgeAccessors &&, msgs::EdgeDirection)>;
|
|
||||||
|
|
||||||
struct VertexIdCmpr {
|
|
||||||
bool operator()(const storage::v3::VertexId *lhs, const storage::v3::VertexId *rhs) const { return *lhs < *rhs; }
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<std::pair<PropertyId, PropertyValue>> ConvertPropertyMap(
|
|
||||||
std::vector<std::pair<PropertyId, Value>> &&properties) {
|
|
||||||
std::vector<std::pair<PropertyId, PropertyValue>> ret;
|
|
||||||
ret.reserve(properties.size());
|
|
||||||
|
|
||||||
std::transform(std::make_move_iterator(properties.begin()), std::make_move_iterator(properties.end()),
|
|
||||||
std::back_inserter(ret), [](std::pair<PropertyId, Value> &&property) {
|
|
||||||
return std::make_pair(property.first, ToPropertyValue(std::move(property.second)));
|
|
||||||
});
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::pair<PropertyId, Value>> FromMap(const std::map<PropertyId, Value> &properties) {
|
|
||||||
std::vector<std::pair<PropertyId, Value>> ret;
|
|
||||||
ret.reserve(properties.size());
|
|
||||||
|
|
||||||
std::transform(properties.begin(), properties.end(), std::back_inserter(ret),
|
|
||||||
[](const auto &property) { return std::make_pair(property.first, property.second); });
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<std::map<PropertyId, Value>> CollectSpecificPropertiesFromAccessor(const VertexAccessor &acc,
|
|
||||||
const std::vector<PropertyId> &props,
|
|
||||||
View view) {
|
|
||||||
std::map<PropertyId, Value> ret;
|
|
||||||
|
|
||||||
for (const auto &prop : props) {
|
|
||||||
auto result = acc.GetProperty(prop, view);
|
|
||||||
if (result.HasError()) {
|
|
||||||
spdlog::debug("Encountered an Error while trying to get a vertex property.");
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
auto &value = result.GetValue();
|
|
||||||
ret.emplace(std::make_pair(prop, FromPropertyValueToValue(std::move(value))));
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<std::map<PropertyId, Value>> PrimaryKeysFromAccessor(const VertexAccessor &acc, View view,
|
|
||||||
const Schemas::Schema *schema) {
|
|
||||||
std::map<PropertyId, Value> ret;
|
|
||||||
auto props = acc.Properties(view);
|
|
||||||
auto maybe_pk = acc.PrimaryKey(view);
|
|
||||||
if (maybe_pk.HasError()) {
|
|
||||||
spdlog::debug("Encountered an error while trying to get vertex primary key.");
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
auto &pk = maybe_pk.GetValue();
|
|
||||||
MG_ASSERT(schema->second.size() == pk.size(), "PrimaryKey size does not match schema!");
|
|
||||||
for (size_t i{0}; i < schema->second.size(); ++i) {
|
|
||||||
ret.emplace(schema->second[i].property_id, FromPropertyValueToValue(std::move(pk[i])));
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<std::map<PropertyId, Value>> CollectAllPropertiesFromAccessor(const VertexAccessor &acc, View view,
|
|
||||||
const Schemas::Schema *schema) {
|
|
||||||
std::map<PropertyId, Value> ret;
|
|
||||||
auto props = acc.Properties(view);
|
|
||||||
if (props.HasError()) {
|
|
||||||
spdlog::debug("Encountered an error while trying to get vertex properties.");
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto &properties = props.GetValue();
|
|
||||||
std::transform(properties.begin(), properties.end(), std::inserter(ret, ret.begin()),
|
|
||||||
[](std::pair<const PropertyId, PropertyValue> &pair) {
|
|
||||||
return std::make_pair(pair.first, FromPropertyValueToValue(std::move(pair.second)));
|
|
||||||
});
|
|
||||||
properties.clear();
|
|
||||||
|
|
||||||
auto pks = PrimaryKeysFromAccessor(acc, view, schema);
|
|
||||||
if (pks) {
|
|
||||||
ret.merge(*pks);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FilterOnVertex(DbAccessor &dba, const storage::v3::VertexAccessor &v_acc, const std::vector<std::string> &filters,
|
|
||||||
const std::string_view node_name) {
|
|
||||||
return std::ranges::all_of(filters, [&node_name, &dba, &v_acc](const auto &filter_expr) {
|
|
||||||
auto res = ComputeExpression(dba, v_acc, std::nullopt, filter_expr, node_name, "");
|
|
||||||
return res.IsBool() && res.ValueBool();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<TypedValue> EvaluateVertexExpressions(DbAccessor &dba, const VertexAccessor &v_acc,
|
|
||||||
const std::vector<std::string> &expressions,
|
|
||||||
std::string_view node_name) {
|
|
||||||
std::vector<TypedValue> evaluated_expressions;
|
|
||||||
evaluated_expressions.reserve(expressions.size());
|
|
||||||
|
|
||||||
std::transform(expressions.begin(), expressions.end(), std::back_inserter(evaluated_expressions),
|
|
||||||
[&dba, &v_acc, &node_name](const auto &expression) {
|
|
||||||
return ComputeExpression(dba, v_acc, std::nullopt, expression, node_name, "");
|
|
||||||
});
|
|
||||||
|
|
||||||
return evaluated_expressions;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct LocalError {};
|
|
||||||
|
|
||||||
std::optional<std::vector<msgs::Label>> FillUpSourceVertexSecondaryLabels(const std::optional<VertexAccessor> &v_acc,
|
|
||||||
const msgs::ExpandOneRequest &req) {
|
|
||||||
auto secondary_labels = v_acc->Labels(View::NEW);
|
|
||||||
if (secondary_labels.HasError()) {
|
|
||||||
spdlog::debug("Encountered an error while trying to get the secondary labels of a vertex. Transaction id: {}",
|
|
||||||
req.transaction_id.logical_id);
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto &sec_labels = secondary_labels.GetValue();
|
|
||||||
std::vector<msgs::Label> msgs_secondary_labels;
|
|
||||||
msgs_secondary_labels.reserve(sec_labels.size());
|
|
||||||
|
|
||||||
std::transform(sec_labels.begin(), sec_labels.end(), std::back_inserter(msgs_secondary_labels),
|
|
||||||
[](auto label_id) { return msgs::Label{.id = label_id}; });
|
|
||||||
|
|
||||||
return msgs_secondary_labels;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<std::map<PropertyId, Value>> FillUpSourceVertexProperties(const std::optional<VertexAccessor> &v_acc,
|
|
||||||
const msgs::ExpandOneRequest &req,
|
|
||||||
storage::v3::View view,
|
|
||||||
const Schemas::Schema *schema) {
|
|
||||||
std::map<PropertyId, Value> src_vertex_properties;
|
|
||||||
|
|
||||||
if (!req.src_vertex_properties) {
|
|
||||||
auto props = v_acc->Properties(View::NEW);
|
|
||||||
if (props.HasError()) {
|
|
||||||
spdlog::debug("Encountered an error while trying to access vertex properties. Transaction id: {}",
|
|
||||||
req.transaction_id.logical_id);
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto &[key, val] : props.GetValue()) {
|
|
||||||
src_vertex_properties.insert(std::make_pair(key, FromPropertyValueToValue(std::move(val))));
|
|
||||||
}
|
|
||||||
auto pks = PrimaryKeysFromAccessor(*v_acc, view, schema);
|
|
||||||
if (pks) {
|
|
||||||
src_vertex_properties.merge(*pks);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (req.src_vertex_properties.value().empty()) {
|
|
||||||
// NOOP
|
|
||||||
} else {
|
|
||||||
for (const auto &prop : req.src_vertex_properties.value()) {
|
|
||||||
auto prop_val = v_acc->GetProperty(prop, View::OLD);
|
|
||||||
if (prop_val.HasError()) {
|
|
||||||
spdlog::debug("Encountered an error while trying to access vertex properties. Transaction id: {}",
|
|
||||||
req.transaction_id.logical_id);
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
src_vertex_properties.insert(std::make_pair(prop, FromPropertyValueToValue(std::move(prop_val.GetValue()))));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return src_vertex_properties;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<std::array<std::vector<EdgeAccessor>, 2>> FillUpConnectingEdges(
|
|
||||||
const std::optional<VertexAccessor> &v_acc, const msgs::ExpandOneRequest &req,
|
|
||||||
const EdgeUniqunessFunction &maybe_filter_based_on_edge_uniquness) {
|
|
||||||
std::vector<EdgeTypeId> edge_types{};
|
|
||||||
edge_types.reserve(req.edge_types.size());
|
|
||||||
std::transform(req.edge_types.begin(), req.edge_types.end(), std::back_inserter(edge_types),
|
|
||||||
[](const msgs::EdgeType &edge_type) { return edge_type.id; });
|
|
||||||
|
|
||||||
std::vector<EdgeAccessor> in_edges;
|
|
||||||
std::vector<EdgeAccessor> out_edges;
|
|
||||||
|
|
||||||
switch (req.direction) {
|
|
||||||
case msgs::EdgeDirection::OUT: {
|
|
||||||
auto out_edges_result = v_acc->OutEdges(View::NEW, edge_types);
|
|
||||||
if (out_edges_result.HasError()) {
|
|
||||||
spdlog::debug("Encountered an error while trying to get out-going EdgeAccessors. Transaction id: {}",
|
|
||||||
req.transaction_id.logical_id);
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
out_edges =
|
|
||||||
maybe_filter_based_on_edge_uniquness(std::move(out_edges_result.GetValue()), msgs::EdgeDirection::OUT);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case msgs::EdgeDirection::IN: {
|
|
||||||
auto in_edges_result = v_acc->InEdges(View::NEW, edge_types);
|
|
||||||
if (in_edges_result.HasError()) {
|
|
||||||
spdlog::debug(
|
|
||||||
"Encountered an error while trying to get in-going EdgeAccessors. Transaction id: {}"[req.transaction_id
|
|
||||||
.logical_id]);
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
in_edges = maybe_filter_based_on_edge_uniquness(std::move(in_edges_result.GetValue()), msgs::EdgeDirection::IN);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case msgs::EdgeDirection::BOTH: {
|
|
||||||
auto in_edges_result = v_acc->InEdges(View::NEW, edge_types);
|
|
||||||
if (in_edges_result.HasError()) {
|
|
||||||
spdlog::debug("Encountered an error while trying to get in-going EdgeAccessors. Transaction id: {}",
|
|
||||||
req.transaction_id.logical_id);
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
in_edges = maybe_filter_based_on_edge_uniquness(std::move(in_edges_result.GetValue()), msgs::EdgeDirection::IN);
|
|
||||||
auto out_edges_result = v_acc->OutEdges(View::NEW, edge_types);
|
|
||||||
if (out_edges_result.HasError()) {
|
|
||||||
spdlog::debug("Encountered an error while trying to get out-going EdgeAccessors. Transaction id: {}",
|
|
||||||
req.transaction_id.logical_id);
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
out_edges =
|
|
||||||
maybe_filter_based_on_edge_uniquness(std::move(out_edges_result.GetValue()), msgs::EdgeDirection::OUT);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return std::array<std::vector<EdgeAccessor>, 2>{in_edges, out_edges};
|
|
||||||
}
|
|
||||||
|
|
||||||
using AllEdgePropertyDataSructure = std::map<PropertyId, msgs::Value>;
|
|
||||||
using SpecificEdgePropertyDataSructure = std::vector<msgs::Value>;
|
|
||||||
|
|
||||||
using AllEdgeProperties = std::tuple<msgs::VertexId, msgs::Gid, AllEdgePropertyDataSructure>;
|
|
||||||
using SpecificEdgeProperties = std::tuple<msgs::VertexId, msgs::Gid, SpecificEdgePropertyDataSructure>;
|
|
||||||
|
|
||||||
using SpecificEdgePropertiesVector = std::vector<SpecificEdgeProperties>;
|
|
||||||
using AllEdgePropertiesVector = std::vector<AllEdgeProperties>;
|
|
||||||
|
|
||||||
using EdgeFiller = std::function<bool(const EdgeAccessor &edge, bool is_in_edge, msgs::ExpandOneResultRow &result_row)>;
|
|
||||||
|
|
||||||
template <bool are_in_edges>
|
|
||||||
bool FillEdges(const std::vector<EdgeAccessor> &edges, msgs::ExpandOneResultRow &row, const EdgeFiller &edge_filler) {
|
|
||||||
for (const auto &edge : edges) {
|
|
||||||
if (!edge_filler(edge, are_in_edges, row)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<msgs::ExpandOneResultRow> GetExpandOneResult(
|
|
||||||
Shard::Accessor &acc, msgs::VertexId src_vertex, const msgs::ExpandOneRequest &req,
|
|
||||||
const EdgeUniqunessFunction &maybe_filter_based_on_edge_uniquness, const EdgeFiller &edge_filler,
|
|
||||||
const Schemas::Schema *schema) {
|
|
||||||
/// Fill up source vertex
|
|
||||||
const auto primary_key = ConvertPropertyVector(src_vertex.second);
|
|
||||||
auto v_acc = acc.FindVertex(primary_key, View::NEW);
|
|
||||||
|
|
||||||
msgs::Vertex source_vertex = {.id = src_vertex};
|
|
||||||
if (const auto maybe_secondary_labels = FillUpSourceVertexSecondaryLabels(v_acc, req); maybe_secondary_labels) {
|
|
||||||
source_vertex.labels = *maybe_secondary_labels;
|
|
||||||
} else {
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<std::map<PropertyId, Value>> src_vertex_properties;
|
|
||||||
src_vertex_properties = FillUpSourceVertexProperties(v_acc, req, storage::v3::View::NEW, schema);
|
|
||||||
|
|
||||||
if (!src_vertex_properties) {
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Fill up connecting edges
|
|
||||||
auto fill_up_connecting_edges = FillUpConnectingEdges(v_acc, req, maybe_filter_based_on_edge_uniquness);
|
|
||||||
if (!fill_up_connecting_edges) {
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto [in_edges, out_edges] = fill_up_connecting_edges.value();
|
|
||||||
|
|
||||||
msgs::ExpandOneResultRow result_row;
|
|
||||||
result_row.src_vertex = std::move(source_vertex);
|
|
||||||
result_row.src_vertex_properties = std::move(*src_vertex_properties);
|
|
||||||
static constexpr bool kInEdges = true;
|
|
||||||
static constexpr bool kOutEdges = false;
|
|
||||||
if (!in_edges.empty() && !FillEdges<kInEdges>(in_edges, result_row, edge_filler)) {
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
if (!out_edges.empty() && !FillEdges<kOutEdges>(out_edges, result_row, edge_filler)) {
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result_row;
|
|
||||||
}
|
|
||||||
|
|
||||||
EdgeUniqunessFunction InitializeEdgeUniqunessFunction(bool only_unique_neighbor_rows) {
|
|
||||||
// Functions to select connecting edges based on uniquness
|
|
||||||
EdgeUniqunessFunction maybe_filter_based_on_edge_uniquness;
|
|
||||||
|
|
||||||
if (only_unique_neighbor_rows) {
|
|
||||||
maybe_filter_based_on_edge_uniquness = [](EdgeAccessors &&edges,
|
|
||||||
msgs::EdgeDirection edge_direction) -> EdgeAccessors {
|
|
||||||
std::function<bool(std::set<const storage::v3::VertexId *, VertexIdCmpr> &, const storage::v3::EdgeAccessor &)>
|
|
||||||
is_edge_unique;
|
|
||||||
switch (edge_direction) {
|
|
||||||
case msgs::EdgeDirection::OUT: {
|
|
||||||
is_edge_unique = [](std::set<const storage::v3::VertexId *, VertexIdCmpr> &other_vertex_set,
|
|
||||||
const storage::v3::EdgeAccessor &edge_acc) {
|
|
||||||
auto [it, insertion_happened] = other_vertex_set.insert(&edge_acc.To());
|
|
||||||
return insertion_happened;
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case msgs::EdgeDirection::IN: {
|
|
||||||
is_edge_unique = [](std::set<const storage::v3::VertexId *, VertexIdCmpr> &other_vertex_set,
|
|
||||||
const storage::v3::EdgeAccessor &edge_acc) {
|
|
||||||
auto [it, insertion_happened] = other_vertex_set.insert(&edge_acc.From());
|
|
||||||
return insertion_happened;
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case msgs::EdgeDirection::BOTH:
|
|
||||||
MG_ASSERT(false, "This is should never happen, msgs::EdgeDirection::BOTH should not be passed here.");
|
|
||||||
}
|
|
||||||
|
|
||||||
EdgeAccessors ret;
|
|
||||||
std::set<const storage::v3::VertexId *, VertexIdCmpr> other_vertex_set;
|
|
||||||
|
|
||||||
for (const auto &edge : edges) {
|
|
||||||
if (is_edge_unique(other_vertex_set, edge)) {
|
|
||||||
ret.emplace_back(edge);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
maybe_filter_based_on_edge_uniquness =
|
|
||||||
[](EdgeAccessors &&edges, msgs::EdgeDirection /*edge_direction*/) -> EdgeAccessors { return std::move(edges); };
|
|
||||||
}
|
|
||||||
|
|
||||||
return maybe_filter_based_on_edge_uniquness;
|
|
||||||
}
|
|
||||||
|
|
||||||
EdgeFiller InitializeEdgeFillerFunction(const msgs::ExpandOneRequest &req) {
|
|
||||||
EdgeFiller edge_filler;
|
|
||||||
|
|
||||||
if (!req.edge_properties) {
|
|
||||||
edge_filler = [transaction_id = req.transaction_id.logical_id](const EdgeAccessor &edge, const bool is_in_edge,
|
|
||||||
msgs::ExpandOneResultRow &result_row) -> bool {
|
|
||||||
auto properties_results = edge.Properties(View::NEW);
|
|
||||||
if (properties_results.HasError()) {
|
|
||||||
spdlog::debug("Encountered an error while trying to get edge properties. Transaction id: {}", transaction_id);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::map<PropertyId, msgs::Value> value_properties;
|
|
||||||
for (auto &[prop_key, prop_val] : properties_results.GetValue()) {
|
|
||||||
value_properties.insert(std::make_pair(prop_key, FromPropertyValueToValue(std::move(prop_val))));
|
|
||||||
}
|
|
||||||
using EdgeWithAllProperties = msgs::ExpandOneResultRow::EdgeWithAllProperties;
|
|
||||||
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 {
|
|
||||||
result_row.out_edges_with_all_properties.push_back(std::move(edges));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
// TODO(gvolfing) - do we want to set the action_successful here?
|
|
||||||
edge_filler = [&req](const EdgeAccessor &edge, const bool is_in_edge,
|
|
||||||
msgs::ExpandOneResultRow &result_row) -> bool {
|
|
||||||
std::vector<msgs::Value> value_properties;
|
|
||||||
value_properties.reserve(req.edge_properties.value().size());
|
|
||||||
for (const auto &edge_prop : req.edge_properties.value()) {
|
|
||||||
auto property_result = edge.GetProperty(edge_prop, View::NEW);
|
|
||||||
if (property_result.HasError()) {
|
|
||||||
spdlog::debug("Encountered an error while trying to get edge properties. Transaction id: {}",
|
|
||||||
req.transaction_id.logical_id);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
value_properties.emplace_back(FromPropertyValueToValue(std::move(property_result.GetValue())));
|
|
||||||
}
|
|
||||||
using EdgeWithSpecificProperties = msgs::ExpandOneResultRow::EdgeWithSpecificProperties;
|
|
||||||
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));
|
|
||||||
} else {
|
|
||||||
result_row.out_edges_with_specific_properties.push_back(std::move(edges));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return edge_filler;
|
|
||||||
}
|
|
||||||
|
|
||||||
}; // namespace
|
|
||||||
msgs::WriteResponses ShardRsm::ApplyWrite(msgs::CreateVerticesRequest &&req) {
|
msgs::WriteResponses ShardRsm::ApplyWrite(msgs::CreateVerticesRequest &&req) {
|
||||||
auto acc = shard_->Access(req.transaction_id);
|
auto acc = shard_->Access(req.transaction_id);
|
||||||
|
|
||||||
bool action_successful = true;
|
std::optional<msgs::ShardError> shard_error;
|
||||||
|
|
||||||
for (auto &new_vertex : req.new_vertices) {
|
for (auto &new_vertex : req.new_vertices) {
|
||||||
/// TODO(gvolfing) Consider other methods than converting. Change either
|
/// TODO(gvolfing) Consider other methods than converting. Change either
|
||||||
/// the way that the property map is stored in the messages, or the
|
/// the way that the property map is stored in the messages, or the
|
||||||
/// signature of CreateVertexAndValidate.
|
/// signature of CreateVertexAndValidate.
|
||||||
auto converted_property_map = ConvertPropertyMap(std::move(new_vertex.properties));
|
auto converted_property_map = ConvertPropertyMap(new_vertex.properties);
|
||||||
|
|
||||||
// TODO(gvolfing) make sure if this conversion is actually needed.
|
// TODO(gvolfing) make sure if this conversion is actually needed.
|
||||||
std::vector<LabelId> converted_label_ids;
|
std::vector<LabelId> converted_label_ids;
|
||||||
@ -492,130 +88,66 @@ msgs::WriteResponses ShardRsm::ApplyWrite(msgs::CreateVerticesRequest &&req) {
|
|||||||
auto result_schema = acc.CreateVertexAndValidate(converted_label_ids, transformed_pk, converted_property_map);
|
auto result_schema = acc.CreateVertexAndValidate(converted_label_ids, transformed_pk, converted_property_map);
|
||||||
|
|
||||||
if (result_schema.HasError()) {
|
if (result_schema.HasError()) {
|
||||||
auto &error = result_schema.GetError();
|
shard_error.emplace(CreateErrorResponse(result_schema.GetError(), req.transaction_id, "creating vertices"));
|
||||||
|
|
||||||
std::visit(
|
|
||||||
[]<typename T>(T &&error) {
|
|
||||||
using ErrorType = std::remove_cvref_t<T>;
|
|
||||||
if constexpr (std::is_same_v<ErrorType, SchemaViolation>) {
|
|
||||||
spdlog::debug("Creating vertex failed with error: SchemaViolation");
|
|
||||||
} else if constexpr (std::is_same_v<ErrorType, Error>) {
|
|
||||||
switch (error) {
|
|
||||||
case Error::DELETED_OBJECT:
|
|
||||||
spdlog::debug("Creating vertex failed with error: DELETED_OBJECT");
|
|
||||||
break;
|
|
||||||
case Error::NONEXISTENT_OBJECT:
|
|
||||||
spdlog::debug("Creating vertex failed with error: NONEXISTENT_OBJECT");
|
|
||||||
break;
|
|
||||||
case Error::SERIALIZATION_ERROR:
|
|
||||||
spdlog::debug("Creating vertex failed with error: SERIALIZATION_ERROR");
|
|
||||||
break;
|
|
||||||
case Error::PROPERTIES_DISABLED:
|
|
||||||
spdlog::debug("Creating vertex failed with error: PROPERTIES_DISABLED");
|
|
||||||
break;
|
|
||||||
case Error::VERTEX_HAS_EDGES:
|
|
||||||
spdlog::debug("Creating vertex failed with error: VERTEX_HAS_EDGES");
|
|
||||||
break;
|
|
||||||
case Error::VERTEX_ALREADY_INSERTED:
|
|
||||||
spdlog::debug("Creating vertex failed with error: VERTEX_ALREADY_INSERTED");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
static_assert(kAlwaysFalse<T>, "Missing type from variant visitor");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
error);
|
|
||||||
|
|
||||||
action_successful = false;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return msgs::CreateVerticesResponse{.success = action_successful};
|
return msgs::CreateVerticesResponse{std::move(shard_error)};
|
||||||
}
|
}
|
||||||
|
|
||||||
msgs::WriteResponses ShardRsm::ApplyWrite(msgs::UpdateVerticesRequest &&req) {
|
msgs::WriteResponses ShardRsm::ApplyWrite(msgs::UpdateVerticesRequest &&req) {
|
||||||
auto acc = shard_->Access(req.transaction_id);
|
auto acc = shard_->Access(req.transaction_id);
|
||||||
|
|
||||||
bool action_successful = true;
|
std::optional<msgs::ShardError> shard_error;
|
||||||
|
for (auto &vertex : req.update_vertices) {
|
||||||
for (auto &vertex : req.new_properties) {
|
auto vertex_to_update = acc.FindVertex(ConvertPropertyVector(std::move(vertex.primary_key)), View::OLD);
|
||||||
if (!action_successful) {
|
if (!vertex_to_update) {
|
||||||
|
shard_error.emplace(msgs::ShardError{common::ErrorCode::OBJECT_NOT_FOUND});
|
||||||
|
spdlog::debug("In transaction {} vertex could not be found while trying to update its properties.",
|
||||||
|
req.transaction_id.logical_id);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto vertex_to_update = acc.FindVertex(ConvertPropertyVector(std::move(vertex.primary_key)), View::OLD);
|
for (const auto label : vertex.add_labels) {
|
||||||
if (!vertex_to_update) {
|
if (const auto maybe_error = vertex_to_update->AddLabelAndValidate(label); maybe_error.HasError()) {
|
||||||
action_successful = false;
|
shard_error.emplace(CreateErrorResponse(maybe_error.GetError(), req.transaction_id, "adding label"));
|
||||||
spdlog::debug("Vertex could not be found while trying to update its properties. Transaction id: {}",
|
break;
|
||||||
req.transaction_id.logical_id);
|
}
|
||||||
continue;
|
}
|
||||||
|
for (const auto label : vertex.remove_labels) {
|
||||||
|
if (const auto maybe_error = vertex_to_update->RemoveLabelAndValidate(label); maybe_error.HasError()) {
|
||||||
|
shard_error.emplace(CreateErrorResponse(maybe_error.GetError(), req.transaction_id, "adding label"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto &update_prop : vertex.property_updates) {
|
for (auto &update_prop : vertex.property_updates) {
|
||||||
auto result_schema =
|
if (const auto result_schema = vertex_to_update->SetPropertyAndValidate(
|
||||||
vertex_to_update->SetPropertyAndValidate(update_prop.first, ToPropertyValue(std::move(update_prop.second)));
|
update_prop.first, ToPropertyValue(std::move(update_prop.second)));
|
||||||
if (result_schema.HasError()) {
|
result_schema.HasError()) {
|
||||||
auto &error = result_schema.GetError();
|
shard_error.emplace(CreateErrorResponse(result_schema.GetError(), req.transaction_id, "adding label"));
|
||||||
|
|
||||||
std::visit(
|
|
||||||
[]<typename T>(T &&error) {
|
|
||||||
using ErrorType = std::remove_cvref_t<T>;
|
|
||||||
if constexpr (std::is_same_v<ErrorType, SchemaViolation>) {
|
|
||||||
spdlog::debug("Updating vertex failed with error: SchemaViolation");
|
|
||||||
} else if constexpr (std::is_same_v<ErrorType, Error>) {
|
|
||||||
switch (error) {
|
|
||||||
case Error::DELETED_OBJECT:
|
|
||||||
spdlog::debug("Updating vertex failed with error: DELETED_OBJECT");
|
|
||||||
break;
|
|
||||||
case Error::NONEXISTENT_OBJECT:
|
|
||||||
spdlog::debug("Updating vertex failed with error: NONEXISTENT_OBJECT");
|
|
||||||
break;
|
|
||||||
case Error::SERIALIZATION_ERROR:
|
|
||||||
spdlog::debug("Updating vertex failed with error: SERIALIZATION_ERROR");
|
|
||||||
break;
|
|
||||||
case Error::PROPERTIES_DISABLED:
|
|
||||||
spdlog::debug("Updating vertex failed with error: PROPERTIES_DISABLED");
|
|
||||||
break;
|
|
||||||
case Error::VERTEX_HAS_EDGES:
|
|
||||||
spdlog::debug("Updating vertex failed with error: VERTEX_HAS_EDGES");
|
|
||||||
break;
|
|
||||||
case Error::VERTEX_ALREADY_INSERTED:
|
|
||||||
spdlog::debug("Updating vertex failed with error: VERTEX_ALREADY_INSERTED");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
static_assert(kAlwaysFalse<T>, "Missing type from variant visitor");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
error);
|
|
||||||
|
|
||||||
action_successful = false;
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return msgs::UpdateVerticesResponse{.success = action_successful};
|
return msgs::UpdateVerticesResponse{std::move(shard_error)};
|
||||||
}
|
}
|
||||||
|
|
||||||
msgs::WriteResponses ShardRsm::ApplyWrite(msgs::DeleteVerticesRequest &&req) {
|
msgs::WriteResponses ShardRsm::ApplyWrite(msgs::DeleteVerticesRequest &&req) {
|
||||||
bool action_successful = true;
|
std::optional<msgs::ShardError> shard_error;
|
||||||
auto acc = shard_->Access(req.transaction_id);
|
auto acc = shard_->Access(req.transaction_id);
|
||||||
|
|
||||||
for (auto &propval : req.primary_keys) {
|
for (auto &propval : req.primary_keys) {
|
||||||
if (!action_successful) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto vertex_acc = acc.FindVertex(ConvertPropertyVector(std::move(propval)), View::OLD);
|
auto vertex_acc = acc.FindVertex(ConvertPropertyVector(std::move(propval)), View::OLD);
|
||||||
|
|
||||||
if (!vertex_acc) {
|
if (!vertex_acc) {
|
||||||
spdlog::debug("Error while trying to delete vertex. Vertex to delete does not exist. Transaction id: {}",
|
shard_error.emplace(msgs::ShardError{common::ErrorCode::OBJECT_NOT_FOUND});
|
||||||
|
spdlog::debug("In transaction {} vertex could not be found while trying to delete it.",
|
||||||
req.transaction_id.logical_id);
|
req.transaction_id.logical_id);
|
||||||
action_successful = false;
|
break;
|
||||||
} else {
|
}
|
||||||
// TODO(gvolfing)
|
// TODO(gvolfing)
|
||||||
// Since we will not have different kinds of deletion types in one transaction,
|
// Since we will not have different kinds of deletion types in one transaction,
|
||||||
// we dont have to enter the switch statement on every iteration. Optimize this.
|
// we dont have to enter the switch statement on every iteration. Optimize this.
|
||||||
@ -623,32 +155,29 @@ msgs::WriteResponses ShardRsm::ApplyWrite(msgs::DeleteVerticesRequest &&req) {
|
|||||||
case msgs::DeleteVerticesRequest::DeletionType::DELETE: {
|
case msgs::DeleteVerticesRequest::DeletionType::DELETE: {
|
||||||
auto result = acc.DeleteVertex(&vertex_acc.value());
|
auto result = acc.DeleteVertex(&vertex_acc.value());
|
||||||
if (result.HasError() || !(result.GetValue().has_value())) {
|
if (result.HasError() || !(result.GetValue().has_value())) {
|
||||||
action_successful = false;
|
shard_error.emplace(CreateErrorResponse(result.GetError(), req.transaction_id, "deleting vertices"));
|
||||||
spdlog::debug("Error while trying to delete vertex. Transaction id: {}", req.transaction_id.logical_id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case msgs::DeleteVerticesRequest::DeletionType::DETACH_DELETE: {
|
case msgs::DeleteVerticesRequest::DeletionType::DETACH_DELETE: {
|
||||||
auto result = acc.DetachDeleteVertex(&vertex_acc.value());
|
auto result = acc.DetachDeleteVertex(&vertex_acc.value());
|
||||||
if (result.HasError() || !(result.GetValue().has_value())) {
|
if (result.HasError() || !(result.GetValue().has_value())) {
|
||||||
action_successful = false;
|
shard_error.emplace(CreateErrorResponse(result.GetError(), req.transaction_id, "deleting vertices"));
|
||||||
spdlog::debug("Error while trying to detach and delete vertex. Transaction id: {}",
|
|
||||||
req.transaction_id.logical_id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (shard_error) {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return msgs::DeleteVerticesResponse{.success = action_successful};
|
return msgs::DeleteVerticesResponse{std::move(shard_error)};
|
||||||
}
|
}
|
||||||
|
|
||||||
msgs::WriteResponses ShardRsm::ApplyWrite(msgs::CreateExpandRequest &&req) {
|
msgs::WriteResponses ShardRsm::ApplyWrite(msgs::CreateExpandRequest &&req) {
|
||||||
auto acc = shard_->Access(req.transaction_id);
|
auto acc = shard_->Access(req.transaction_id);
|
||||||
bool action_successful = true;
|
std::optional<msgs::ShardError> shard_error;
|
||||||
|
|
||||||
for (auto &new_expand : req.new_expands) {
|
for (auto &new_expand : req.new_expands) {
|
||||||
const auto from_vertex_id =
|
const auto from_vertex_id =
|
||||||
@ -658,7 +187,8 @@ msgs::WriteResponses ShardRsm::ApplyWrite(msgs::CreateExpandRequest &&req) {
|
|||||||
VertexId{new_expand.dest_vertex.first.id, ConvertPropertyVector(std::move(new_expand.dest_vertex.second))};
|
VertexId{new_expand.dest_vertex.first.id, ConvertPropertyVector(std::move(new_expand.dest_vertex.second))};
|
||||||
|
|
||||||
if (!(shard_->IsVertexBelongToShard(from_vertex_id) || shard_->IsVertexBelongToShard(to_vertex_id))) {
|
if (!(shard_->IsVertexBelongToShard(from_vertex_id) || shard_->IsVertexBelongToShard(to_vertex_id))) {
|
||||||
action_successful = false;
|
shard_error = msgs::ShardError{common::ErrorCode::OBJECT_NOT_FOUND,
|
||||||
|
"Error while trying to insert edge, none of the vertices belong to this shard"};
|
||||||
spdlog::debug("Error while trying to insert edge, none of the vertices belong to this shard. Transaction id: {}",
|
spdlog::debug("Error while trying to insert edge, none of the vertices belong to this shard. Transaction id: {}",
|
||||||
req.transaction_id.logical_id);
|
req.transaction_id.logical_id);
|
||||||
break;
|
break;
|
||||||
@ -670,18 +200,18 @@ msgs::WriteResponses ShardRsm::ApplyWrite(msgs::CreateExpandRequest &&req) {
|
|||||||
if (!new_expand.properties.empty()) {
|
if (!new_expand.properties.empty()) {
|
||||||
for (const auto &[property, value] : new_expand.properties) {
|
for (const auto &[property, value] : new_expand.properties) {
|
||||||
if (const auto maybe_error = edge.SetProperty(property, ToPropertyValue(value)); maybe_error.HasError()) {
|
if (const auto maybe_error = edge.SetProperty(property, ToPropertyValue(value)); maybe_error.HasError()) {
|
||||||
action_successful = false;
|
shard_error.emplace(
|
||||||
spdlog::debug("Setting edge property was not successful. Transaction id: {}",
|
CreateErrorResponse(maybe_error.GetError(), req.transaction_id, "setting edge property"));
|
||||||
req.transaction_id.logical_id);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!action_successful) {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
if (shard_error) {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
action_successful = false;
|
// TODO Code for this
|
||||||
|
shard_error = msgs::ShardError{common::ErrorCode::OBJECT_NOT_FOUND};
|
||||||
spdlog::debug("Creating edge was not successful. Transaction id: {}", req.transaction_id.logical_id);
|
spdlog::debug("Creating edge was not successful. Transaction id: {}", req.transaction_id.logical_id);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -691,24 +221,22 @@ msgs::WriteResponses ShardRsm::ApplyWrite(msgs::CreateExpandRequest &&req) {
|
|||||||
for (auto &[edge_prop_key, edge_prop_val] : new_expand.properties) {
|
for (auto &[edge_prop_key, edge_prop_val] : new_expand.properties) {
|
||||||
auto set_result = edge_acc->SetProperty(edge_prop_key, ToPropertyValue(std::move(edge_prop_val)));
|
auto set_result = edge_acc->SetProperty(edge_prop_key, ToPropertyValue(std::move(edge_prop_val)));
|
||||||
if (set_result.HasError()) {
|
if (set_result.HasError()) {
|
||||||
action_successful = false;
|
shard_error.emplace(CreateErrorResponse(set_result.GetError(), req.transaction_id, "adding edge property"));
|
||||||
spdlog::debug("Adding property to edge was not successful. Transaction id: {}",
|
|
||||||
req.transaction_id.logical_id);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return msgs::CreateExpandResponse{.success = action_successful};
|
return msgs::CreateExpandResponse{std::move(shard_error)};
|
||||||
}
|
}
|
||||||
|
|
||||||
msgs::WriteResponses ShardRsm::ApplyWrite(msgs::DeleteEdgesRequest &&req) {
|
msgs::WriteResponses ShardRsm::ApplyWrite(msgs::DeleteEdgesRequest &&req) {
|
||||||
bool action_successful = true;
|
std::optional<msgs::ShardError> shard_error;
|
||||||
auto acc = shard_->Access(req.transaction_id);
|
auto acc = shard_->Access(req.transaction_id);
|
||||||
|
|
||||||
for (auto &edge : req.edges) {
|
for (auto &edge : req.edges) {
|
||||||
if (!action_successful) {
|
if (shard_error) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -716,41 +244,38 @@ msgs::WriteResponses ShardRsm::ApplyWrite(msgs::DeleteEdgesRequest &&req) {
|
|||||||
VertexId(edge.dst.first.id, ConvertPropertyVector(std::move(edge.dst.second))),
|
VertexId(edge.dst.first.id, ConvertPropertyVector(std::move(edge.dst.second))),
|
||||||
Gid::FromUint(edge.id.gid));
|
Gid::FromUint(edge.id.gid));
|
||||||
if (edge_acc.HasError() || !edge_acc.HasValue()) {
|
if (edge_acc.HasError() || !edge_acc.HasValue()) {
|
||||||
spdlog::debug("Error while trying to delete edge. Transaction id: {}", req.transaction_id.logical_id);
|
shard_error.emplace(CreateErrorResponse(edge_acc.GetError(), req.transaction_id, "delete edge"));
|
||||||
action_successful = false;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return msgs::DeleteEdgesResponse{.success = action_successful};
|
return msgs::DeleteEdgesResponse{std::move(shard_error)};
|
||||||
}
|
}
|
||||||
|
|
||||||
msgs::WriteResponses ShardRsm::ApplyWrite(msgs::UpdateEdgesRequest &&req) {
|
msgs::WriteResponses ShardRsm::ApplyWrite(msgs::UpdateEdgesRequest &&req) {
|
||||||
// TODO(antaljanosbenjamin): handle when the vertex is the destination vertex
|
// TODO(antaljanosbenjamin): handle when the vertex is the destination vertex
|
||||||
auto acc = shard_->Access(req.transaction_id);
|
auto acc = shard_->Access(req.transaction_id);
|
||||||
|
|
||||||
bool action_successful = true;
|
std::optional<msgs::ShardError> shard_error;
|
||||||
|
|
||||||
for (auto &edge : req.new_properties) {
|
for (auto &edge : req.new_properties) {
|
||||||
if (!action_successful) {
|
if (shard_error) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto vertex_acc = acc.FindVertex(ConvertPropertyVector(std::move(edge.src.second)), View::OLD);
|
auto vertex_acc = acc.FindVertex(ConvertPropertyVector(std::move(edge.src.second)), View::OLD);
|
||||||
if (!vertex_acc) {
|
if (!vertex_acc) {
|
||||||
action_successful = false;
|
shard_error = msgs::ShardError{common::ErrorCode::OBJECT_NOT_FOUND, "Source vertex was not found"};
|
||||||
spdlog::debug("Encountered an error while trying to acquire VertexAccessor with transaction id: {}",
|
spdlog::debug("Encountered an error while trying to acquire VertexAccessor with transaction id: {}",
|
||||||
req.transaction_id.logical_id);
|
req.transaction_id.logical_id);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Since we are using the source vertex of the edge we are only intrested
|
// Since we are using the source vertex of the edge we are only interested
|
||||||
// in the vertex's out-going edges
|
// in the vertex's out-going edges
|
||||||
auto edges_res = vertex_acc->OutEdges(View::OLD);
|
auto edges_res = vertex_acc->OutEdges(View::OLD);
|
||||||
if (edges_res.HasError()) {
|
if (edges_res.HasError()) {
|
||||||
action_successful = false;
|
shard_error.emplace(CreateErrorResponse(edges_res.GetError(), req.transaction_id, "update edge"));
|
||||||
spdlog::debug("Encountered an error while trying to acquire EdgeAccessor with transaction id: {}",
|
|
||||||
req.transaction_id.logical_id);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -766,27 +291,28 @@ msgs::WriteResponses ShardRsm::ApplyWrite(msgs::UpdateEdgesRequest &&req) {
|
|||||||
// Check if the property was set if SetProperty does not do that itself.
|
// Check if the property was set if SetProperty does not do that itself.
|
||||||
auto res = edge_accessor.SetProperty(key, ToPropertyValue(std::move(value)));
|
auto res = edge_accessor.SetProperty(key, ToPropertyValue(std::move(value)));
|
||||||
if (res.HasError()) {
|
if (res.HasError()) {
|
||||||
spdlog::debug("Encountered an error while trying to set the property of an Edge with transaction id: {}",
|
// TODO(jbajic) why not set action unsuccessful here?
|
||||||
req.transaction_id.logical_id);
|
shard_error.emplace(CreateErrorResponse(edges_res.GetError(), req.transaction_id, "update edge"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!edge_accessor_did_match) {
|
if (!edge_accessor_did_match) {
|
||||||
action_successful = false;
|
// TODO(jbajic) Do we need this
|
||||||
|
shard_error = msgs::ShardError{common::ErrorCode::OBJECT_NOT_FOUND, "Edge was not found"};
|
||||||
spdlog::debug("Could not find the Edge with the specified Gid. Transaction id: {}",
|
spdlog::debug("Could not find the Edge with the specified Gid. Transaction id: {}",
|
||||||
req.transaction_id.logical_id);
|
req.transaction_id.logical_id);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return msgs::UpdateEdgesResponse{.success = action_successful};
|
return msgs::UpdateEdgesResponse{std::move(shard_error)};
|
||||||
}
|
}
|
||||||
|
|
||||||
msgs::ReadResponses ShardRsm::HandleRead(msgs::ScanVerticesRequest &&req) {
|
msgs::ReadResponses ShardRsm::HandleRead(msgs::ScanVerticesRequest &&req) {
|
||||||
auto acc = shard_->Access(req.transaction_id);
|
auto acc = shard_->Access(req.transaction_id);
|
||||||
bool action_successful = true;
|
std::optional<msgs::ShardError> shard_error;
|
||||||
|
|
||||||
std::vector<msgs::ScanResultRow> results;
|
std::vector<msgs::ScanResultRow> results;
|
||||||
if (req.batch_limit) {
|
if (req.batch_limit) {
|
||||||
@ -811,24 +337,24 @@ msgs::ReadResponses ShardRsm::HandleRead(msgs::ScanVerticesRequest &&req) {
|
|||||||
EvaluateVertexExpressions(dba, vertex, req.vertex_expressions, expr::identifier_node_symbol));
|
EvaluateVertexExpressions(dba, vertex, req.vertex_expressions, expr::identifier_node_symbol));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::map<PropertyId, Value>> found_props;
|
auto found_props = std::invoke([&]() {
|
||||||
|
|
||||||
if (req.props_to_return) {
|
if (req.props_to_return) {
|
||||||
found_props = CollectSpecificPropertiesFromAccessor(vertex, req.props_to_return.value(), view);
|
return CollectSpecificPropertiesFromAccessor(vertex, req.props_to_return.value(), view);
|
||||||
} else {
|
|
||||||
const auto *schema = shard_->GetSchema(shard_->PrimaryLabel());
|
|
||||||
found_props = CollectAllPropertiesFromAccessor(vertex, view, schema);
|
|
||||||
}
|
}
|
||||||
|
const auto *schema = shard_->GetSchema(shard_->PrimaryLabel());
|
||||||
|
MG_ASSERT(schema);
|
||||||
|
return CollectAllPropertiesFromAccessor(vertex, view, *schema);
|
||||||
|
});
|
||||||
|
|
||||||
// TODO(gvolfing) -VERIFY-
|
// TODO(gvolfing) -VERIFY-
|
||||||
// Vertex is separated from the properties in the response.
|
// Vertex is separated from the properties in the response.
|
||||||
// Is it useful to return just a vertex without the properties?
|
// Is it useful to return just a vertex without the properties?
|
||||||
if (!found_props) {
|
if (found_props.HasError()) {
|
||||||
action_successful = false;
|
shard_error = msgs::ShardError{common::ErrorCode::OBJECT_NOT_FOUND, "Requested properties were not found!"};
|
||||||
}
|
}
|
||||||
|
|
||||||
results.emplace_back(msgs::ScanResultRow{.vertex = ConstructValueVertex(vertex, view).vertex_v,
|
results.emplace_back(msgs::ScanResultRow{.vertex = ConstructValueVertex(vertex, view).vertex_v,
|
||||||
.props = FromMap(found_props.value()),
|
.props = FromMap(found_props.GetValue()),
|
||||||
.evaluated_vertex_expressions = std::move(expression_results)});
|
.evaluated_vertex_expressions = std::move(expression_results)});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -836,18 +362,18 @@ msgs::ReadResponses ShardRsm::HandleRead(msgs::ScanVerticesRequest &&req) {
|
|||||||
uint64_t sample_counter{0};
|
uint64_t sample_counter{0};
|
||||||
auto vertex_iterable = acc.Vertices(view);
|
auto vertex_iterable = acc.Vertices(view);
|
||||||
if (!req.order_bys.empty()) {
|
if (!req.order_bys.empty()) {
|
||||||
const auto ordered = OrderByElements(acc, dba, vertex_iterable, req.order_bys);
|
const auto ordered = OrderByVertices(dba, vertex_iterable, req.order_bys);
|
||||||
// we are traversing Elements
|
// we are traversing Elements
|
||||||
auto it = GetStartOrderedElementsIterator(ordered, start_id, View(req.storage_view));
|
auto it = GetStartOrderedElementsIterator(ordered, start_id, View(req.storage_view));
|
||||||
for (; it != ordered.end(); ++it) {
|
for (; it != ordered.end(); ++it) {
|
||||||
emplace_scan_result(it->vertex_acc);
|
emplace_scan_result(it->object_acc);
|
||||||
++sample_counter;
|
++sample_counter;
|
||||||
if (req.batch_limit && sample_counter == req.batch_limit) {
|
if (req.batch_limit && sample_counter == req.batch_limit) {
|
||||||
// Reached the maximum specified batch size.
|
// Reached the maximum specified batch size.
|
||||||
// Get the next element before exiting.
|
// Get the next element before exiting.
|
||||||
++it;
|
++it;
|
||||||
if (it != ordered.end()) {
|
if (it != ordered.end()) {
|
||||||
const auto &next_vertex = it->vertex_acc;
|
const auto &next_vertex = it->object_acc;
|
||||||
next_start_id = ConstructValueVertex(next_vertex, view).vertex_v.id;
|
next_start_id = ConstructValueVertex(next_vertex, view).vertex_v.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -872,10 +398,8 @@ msgs::ReadResponses ShardRsm::HandleRead(msgs::ScanVerticesRequest &&req) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
msgs::ScanVerticesResponse resp{};
|
msgs::ScanVerticesResponse resp{.error = std::move(shard_error)};
|
||||||
resp.success = action_successful;
|
if (!resp.error) {
|
||||||
|
|
||||||
if (action_successful) {
|
|
||||||
resp.next_start_id = next_start_id;
|
resp.next_start_id = next_start_id;
|
||||||
resp.results = std::move(results);
|
resp.results = std::move(results);
|
||||||
}
|
}
|
||||||
@ -885,45 +409,96 @@ msgs::ReadResponses ShardRsm::HandleRead(msgs::ScanVerticesRequest &&req) {
|
|||||||
|
|
||||||
msgs::ReadResponses ShardRsm::HandleRead(msgs::ExpandOneRequest &&req) {
|
msgs::ReadResponses ShardRsm::HandleRead(msgs::ExpandOneRequest &&req) {
|
||||||
auto acc = shard_->Access(req.transaction_id);
|
auto acc = shard_->Access(req.transaction_id);
|
||||||
bool action_successful = true;
|
std::optional<msgs::ShardError> shard_error;
|
||||||
|
|
||||||
std::vector<msgs::ExpandOneResultRow> results;
|
std::vector<msgs::ExpandOneResultRow> results;
|
||||||
|
const auto batch_limit = req.limit;
|
||||||
|
auto dba = DbAccessor{&acc};
|
||||||
|
|
||||||
auto maybe_filter_based_on_edge_uniquness = InitializeEdgeUniqunessFunction(req.only_unique_neighbor_rows);
|
auto maybe_filter_based_on_edge_uniqueness = InitializeEdgeUniquenessFunction(req.only_unique_neighbor_rows);
|
||||||
auto edge_filler = InitializeEdgeFillerFunction(req);
|
auto edge_filler = InitializeEdgeFillerFunction(req);
|
||||||
|
|
||||||
|
std::vector<VertexAccessor> vertex_accessors;
|
||||||
|
vertex_accessors.reserve(req.src_vertices.size());
|
||||||
for (auto &src_vertex : req.src_vertices) {
|
for (auto &src_vertex : req.src_vertices) {
|
||||||
// Get Vertex acc
|
// Get Vertex acc
|
||||||
auto src_vertex_acc_opt = acc.FindVertex(ConvertPropertyVector((src_vertex.second)), View::NEW);
|
auto src_vertex_acc_opt = acc.FindVertex(ConvertPropertyVector((src_vertex.second)), View::NEW);
|
||||||
if (!src_vertex_acc_opt) {
|
if (!src_vertex_acc_opt) {
|
||||||
action_successful = false;
|
shard_error = msgs::ShardError{common::ErrorCode::OBJECT_NOT_FOUND, "Source vertex was not found."};
|
||||||
spdlog::debug("Encountered an error while trying to obtain VertexAccessor. Transaction id: {}",
|
spdlog::debug("Encountered an error while trying to obtain VertexAccessor. Transaction id: {}",
|
||||||
req.transaction_id.logical_id);
|
req.transaction_id.logical_id);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!req.filters.empty()) {
|
if (!req.filters.empty()) {
|
||||||
// NOTE - DbAccessor might get removed in the future.
|
// NOTE - DbAccessor might get removed in the future.
|
||||||
auto dba = DbAccessor{&acc};
|
|
||||||
const bool eval = FilterOnVertex(dba, src_vertex_acc_opt.value(), req.filters, expr::identifier_node_symbol);
|
const bool eval = FilterOnVertex(dba, src_vertex_acc_opt.value(), req.filters, expr::identifier_node_symbol);
|
||||||
if (!eval) {
|
if (!eval) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto result = GetExpandOneResult(acc, src_vertex, req, maybe_filter_based_on_edge_uniquness, edge_filler,
|
|
||||||
shard_->GetSchema(shard_->PrimaryLabel()));
|
|
||||||
|
|
||||||
if (!result) {
|
vertex_accessors.emplace_back(src_vertex_acc_opt.value());
|
||||||
action_successful = false;
|
}
|
||||||
|
|
||||||
|
if (!req.order_by_vertices.empty()) {
|
||||||
|
// Can we do differently to avoid this? We need OrderByElements but currently it returns vector<Element>, so this
|
||||||
|
// workaround is here to avoid more duplication later
|
||||||
|
auto local_sorted_vertices = OrderByVertices(dba, vertex_accessors, req.order_by_vertices);
|
||||||
|
vertex_accessors.clear();
|
||||||
|
std::transform(local_sorted_vertices.begin(), local_sorted_vertices.end(), std::back_inserter(vertex_accessors),
|
||||||
|
[](auto &vertex) { return vertex.object_acc; });
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &src_vertex_acc : vertex_accessors) {
|
||||||
|
auto label_id = src_vertex_acc.PrimaryLabel(View::NEW);
|
||||||
|
if (label_id.HasError()) {
|
||||||
|
shard_error.emplace(CreateErrorResponse(label_id.GetError(), req.transaction_id, "getting label"));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto primary_key = src_vertex_acc.PrimaryKey(View::NEW);
|
||||||
|
if (primary_key.HasError()) {
|
||||||
|
shard_error.emplace(CreateErrorResponse(primary_key.GetError(), req.transaction_id, "getting primary key"));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
results.emplace_back(result.value());
|
msgs::VertexId src_vertex(msgs::Label{.id = *label_id}, conversions::ConvertValueVector(*primary_key));
|
||||||
|
|
||||||
|
auto maybe_result = std::invoke([&]() {
|
||||||
|
if (req.order_by_edges.empty()) {
|
||||||
|
const auto *schema = shard_->GetSchema(shard_->PrimaryLabel());
|
||||||
|
MG_ASSERT(schema);
|
||||||
|
return GetExpandOneResult(acc, src_vertex, req, maybe_filter_based_on_edge_uniqueness, edge_filler, *schema);
|
||||||
|
}
|
||||||
|
auto [in_edge_accessors, out_edge_accessors] = GetEdgesFromVertex(src_vertex_acc, req.direction);
|
||||||
|
const auto in_ordered_edges = OrderByEdges(dba, in_edge_accessors, req.order_by_edges, src_vertex_acc);
|
||||||
|
const auto out_ordered_edges = OrderByEdges(dba, out_edge_accessors, req.order_by_edges, src_vertex_acc);
|
||||||
|
|
||||||
|
std::vector<EdgeAccessor> in_edge_ordered_accessors;
|
||||||
|
std::transform(in_ordered_edges.begin(), in_ordered_edges.end(), std::back_inserter(in_edge_ordered_accessors),
|
||||||
|
[](const auto &edge_element) { return edge_element.object_acc; });
|
||||||
|
|
||||||
|
std::vector<EdgeAccessor> out_edge_ordered_accessors;
|
||||||
|
std::transform(out_ordered_edges.begin(), out_ordered_edges.end(), std::back_inserter(out_edge_ordered_accessors),
|
||||||
|
[](const auto &edge_element) { return edge_element.object_acc; });
|
||||||
|
const auto *schema = shard_->GetSchema(shard_->PrimaryLabel());
|
||||||
|
MG_ASSERT(schema);
|
||||||
|
return GetExpandOneResult(src_vertex_acc, src_vertex, req, in_edge_ordered_accessors, out_edge_ordered_accessors,
|
||||||
|
maybe_filter_based_on_edge_uniqueness, edge_filler, *schema);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (maybe_result.HasError()) {
|
||||||
|
shard_error.emplace(CreateErrorResponse(primary_key.GetError(), req.transaction_id, "getting primary key"));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
msgs::ExpandOneResponse resp{};
|
results.emplace_back(std::move(maybe_result.GetValue()));
|
||||||
resp.success = action_successful;
|
if (batch_limit.has_value() && results.size() >= batch_limit.value()) {
|
||||||
if (action_successful) {
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
msgs::ExpandOneResponse resp{.error = std::move(shard_error)};
|
||||||
|
if (!resp.error) {
|
||||||
resp.result = std::move(results);
|
resp.result = std::move(results);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -932,7 +507,7 @@ msgs::ReadResponses ShardRsm::HandleRead(msgs::ExpandOneRequest &&req) {
|
|||||||
|
|
||||||
msgs::WriteResponses ShardRsm::ApplyWrite(msgs::CommitRequest &&req) {
|
msgs::WriteResponses ShardRsm::ApplyWrite(msgs::CommitRequest &&req) {
|
||||||
shard_->Access(req.transaction_id).Commit(req.commit_timestamp);
|
shard_->Access(req.transaction_id).Commit(req.commit_timestamp);
|
||||||
return msgs::CommitResponse{true};
|
return msgs::CommitResponse{};
|
||||||
};
|
};
|
||||||
|
|
||||||
// NOLINTNEXTLINE(readability-convert-member-functions-to-static)
|
// NOLINTNEXTLINE(readability-convert-member-functions-to-static)
|
||||||
|
@ -21,9 +21,6 @@
|
|||||||
|
|
||||||
namespace memgraph::storage::v3 {
|
namespace memgraph::storage::v3 {
|
||||||
|
|
||||||
template <typename>
|
|
||||||
constexpr auto kAlwaysFalse = false;
|
|
||||||
|
|
||||||
class ShardRsm {
|
class ShardRsm {
|
||||||
std::unique_ptr<Shard> shard_;
|
std::unique_ptr<Shard> shard_;
|
||||||
|
|
||||||
|
@ -129,4 +129,27 @@ inline std::vector<Value> ConvertValueVector(const std::vector<v3::PropertyValue
|
|||||||
inline msgs::VertexId ToMsgsVertexId(const v3::VertexId &vertex_id) {
|
inline msgs::VertexId ToMsgsVertexId(const v3::VertexId &vertex_id) {
|
||||||
return {msgs::Label{vertex_id.primary_label}, ConvertValueVector(vertex_id.primary_key)};
|
return {msgs::Label{vertex_id.primary_label}, ConvertValueVector(vertex_id.primary_key)};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline std::vector<std::pair<v3::PropertyId, v3::PropertyValue>> ConvertPropertyMap(
|
||||||
|
std::vector<std::pair<v3::PropertyId, Value>> &properties) {
|
||||||
|
std::vector<std::pair<v3::PropertyId, v3::PropertyValue>> ret;
|
||||||
|
ret.reserve(properties.size());
|
||||||
|
|
||||||
|
std::transform(std::make_move_iterator(properties.begin()), std::make_move_iterator(properties.end()),
|
||||||
|
std::back_inserter(ret), [](std::pair<v3::PropertyId, Value> &&property) {
|
||||||
|
return std::make_pair(property.first, ToPropertyValue(std::move(property.second)));
|
||||||
|
});
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::vector<std::pair<PropertyId, Value>> FromMap(const std::map<PropertyId, Value> &properties) {
|
||||||
|
std::vector<std::pair<PropertyId, Value>> ret;
|
||||||
|
ret.reserve(properties.size());
|
||||||
|
|
||||||
|
std::transform(properties.begin(), properties.end(), std::back_inserter(ret),
|
||||||
|
[](const auto &property) { return std::make_pair(property.first, property.second); });
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
} // namespace memgraph::storage::conversions
|
} // namespace memgraph::storage::conversions
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
#include "storage/v3/key_store.hpp"
|
#include "storage/v3/key_store.hpp"
|
||||||
#include "storage/v3/mvcc.hpp"
|
#include "storage/v3/mvcc.hpp"
|
||||||
#include "storage/v3/property_value.hpp"
|
#include "storage/v3/property_value.hpp"
|
||||||
|
#include "storage/v3/result.hpp"
|
||||||
#include "storage/v3/shard.hpp"
|
#include "storage/v3/shard.hpp"
|
||||||
#include "storage/v3/shard_operation_result.hpp"
|
|
||||||
#include "storage/v3/vertex.hpp"
|
#include "storage/v3/vertex.hpp"
|
||||||
#include "utils/logging.hpp"
|
#include "utils/logging.hpp"
|
||||||
#include "utils/memory_tracker.hpp"
|
#include "utils/memory_tracker.hpp"
|
||||||
@ -80,12 +80,12 @@ bool VertexAccessor::IsVisible(View view) const {
|
|||||||
return exists && (for_deleted_ || !deleted);
|
return exists && (for_deleted_ || !deleted);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<bool> VertexAccessor::AddLabel(LabelId label) {
|
ShardResult<bool> VertexAccessor::AddLabel(LabelId label) {
|
||||||
utils::MemoryTracker::OutOfMemoryExceptionEnabler oom_exception;
|
utils::MemoryTracker::OutOfMemoryExceptionEnabler oom_exception;
|
||||||
|
|
||||||
if (!PrepareForWrite(transaction_, vertex_)) return Error::SERIALIZATION_ERROR;
|
if (!PrepareForWrite(transaction_, vertex_)) return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR);
|
||||||
|
|
||||||
if (vertex_->deleted) return Error::DELETED_OBJECT;
|
if (vertex_->deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
|
||||||
|
|
||||||
if (std::find(vertex_->labels.begin(), vertex_->labels.end(), label) != vertex_->labels.end()) return false;
|
if (std::find(vertex_->labels.begin(), vertex_->labels.end(), label) != vertex_->labels.end()) return false;
|
||||||
|
|
||||||
@ -98,15 +98,15 @@ Result<bool> VertexAccessor::AddLabel(LabelId label) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ShardOperationResult<bool> VertexAccessor::AddLabelAndValidate(LabelId label) {
|
ShardResult<bool> VertexAccessor::AddLabelAndValidate(LabelId label) {
|
||||||
if (const auto maybe_violation_error = vertex_validator_->ValidateAddLabel(label); maybe_violation_error) {
|
if (const auto maybe_violation_error = vertex_validator_->ValidateAddLabel(label); maybe_violation_error.HasError()) {
|
||||||
return {*maybe_violation_error};
|
return {maybe_violation_error.GetError()};
|
||||||
}
|
}
|
||||||
utils::MemoryTracker::OutOfMemoryExceptionEnabler oom_exception;
|
utils::MemoryTracker::OutOfMemoryExceptionEnabler oom_exception;
|
||||||
|
|
||||||
if (!PrepareForWrite(transaction_, vertex_)) return {Error::SERIALIZATION_ERROR};
|
if (!PrepareForWrite(transaction_, vertex_)) return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR);
|
||||||
|
|
||||||
if (vertex_->deleted) return {Error::DELETED_OBJECT};
|
if (vertex_->deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
|
||||||
|
|
||||||
if (std::find(vertex_->labels.begin(), vertex_->labels.end(), label) != vertex_->labels.end()) return false;
|
if (std::find(vertex_->labels.begin(), vertex_->labels.end(), label) != vertex_->labels.end()) return false;
|
||||||
|
|
||||||
@ -119,10 +119,10 @@ ShardOperationResult<bool> VertexAccessor::AddLabelAndValidate(LabelId label) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<bool> VertexAccessor::RemoveLabel(LabelId label) {
|
ShardResult<bool> VertexAccessor::RemoveLabel(LabelId label) {
|
||||||
if (!PrepareForWrite(transaction_, vertex_)) return Error::SERIALIZATION_ERROR;
|
if (!PrepareForWrite(transaction_, vertex_)) return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR);
|
||||||
|
|
||||||
if (vertex_->deleted) return Error::DELETED_OBJECT;
|
if (vertex_->deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
|
||||||
|
|
||||||
auto it = std::find(vertex_->labels.begin(), vertex_->labels.end(), label);
|
auto it = std::find(vertex_->labels.begin(), vertex_->labels.end(), label);
|
||||||
if (it == vertex_->labels.end()) return false;
|
if (it == vertex_->labels.end()) return false;
|
||||||
@ -134,14 +134,15 @@ Result<bool> VertexAccessor::RemoveLabel(LabelId label) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ShardOperationResult<bool> VertexAccessor::RemoveLabelAndValidate(LabelId label) {
|
ShardResult<bool> VertexAccessor::RemoveLabelAndValidate(LabelId label) {
|
||||||
if (const auto maybe_violation_error = vertex_validator_->ValidateRemoveLabel(label); maybe_violation_error) {
|
if (const auto maybe_violation_error = vertex_validator_->ValidateRemoveLabel(label);
|
||||||
return {*maybe_violation_error};
|
maybe_violation_error.HasError()) {
|
||||||
|
return {maybe_violation_error.GetError()};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!PrepareForWrite(transaction_, vertex_)) return {Error::SERIALIZATION_ERROR};
|
if (!PrepareForWrite(transaction_, vertex_)) return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR);
|
||||||
|
|
||||||
if (vertex_->deleted) return {Error::DELETED_OBJECT};
|
if (vertex_->deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
|
||||||
|
|
||||||
auto it = std::find(vertex_->labels.begin(), vertex_->labels.end(), label);
|
auto it = std::find(vertex_->labels.begin(), vertex_->labels.end(), label);
|
||||||
if (it == vertex_->labels.end()) return false;
|
if (it == vertex_->labels.end()) return false;
|
||||||
@ -153,9 +154,9 @@ ShardOperationResult<bool> VertexAccessor::RemoveLabelAndValidate(LabelId label)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<bool> VertexAccessor::HasLabel(View view, LabelId label) const { return HasLabel(label, view); }
|
ShardResult<bool> VertexAccessor::HasLabel(View view, LabelId label) const { return HasLabel(label, view); }
|
||||||
|
|
||||||
Result<bool> VertexAccessor::HasLabel(LabelId label, View view) const {
|
ShardResult<bool> VertexAccessor::HasLabel(LabelId label, View view) const {
|
||||||
bool exists = true;
|
bool exists = true;
|
||||||
bool deleted = false;
|
bool deleted = false;
|
||||||
bool has_label = false;
|
bool has_label = false;
|
||||||
@ -197,12 +198,12 @@ Result<bool> VertexAccessor::HasLabel(LabelId label, View view) const {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (!exists) return Error::NONEXISTENT_OBJECT;
|
if (!exists) return SHARD_ERROR(ErrorCode::NONEXISTENT_OBJECT);
|
||||||
if (!for_deleted_ && deleted) return Error::DELETED_OBJECT;
|
if (!for_deleted_ && deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
|
||||||
return has_label;
|
return has_label;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<LabelId> VertexAccessor::PrimaryLabel(const View view) const {
|
ShardResult<LabelId> VertexAccessor::PrimaryLabel(const View view) const {
|
||||||
if (const auto result = CheckVertexExistence(view); result.HasError()) {
|
if (const auto result = CheckVertexExistence(view); result.HasError()) {
|
||||||
return result.GetError();
|
return result.GetError();
|
||||||
}
|
}
|
||||||
@ -210,21 +211,21 @@ Result<LabelId> VertexAccessor::PrimaryLabel(const View view) const {
|
|||||||
return vertex_validator_->primary_label_;
|
return vertex_validator_->primary_label_;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<PrimaryKey> VertexAccessor::PrimaryKey(const View view) const {
|
ShardResult<PrimaryKey> VertexAccessor::PrimaryKey(const View view) const {
|
||||||
if (const auto result = CheckVertexExistence(view); result.HasError()) {
|
if (const auto result = CheckVertexExistence(view); result.HasError()) {
|
||||||
return result.GetError();
|
return result.GetError();
|
||||||
}
|
}
|
||||||
return vertex_->keys.Keys();
|
return vertex_->keys.Keys();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<VertexId> VertexAccessor::Id(View view) const {
|
ShardResult<VertexId> VertexAccessor::Id(View view) const {
|
||||||
if (const auto result = CheckVertexExistence(view); result.HasError()) {
|
if (const auto result = CheckVertexExistence(view); result.HasError()) {
|
||||||
return result.GetError();
|
return result.GetError();
|
||||||
}
|
}
|
||||||
return VertexId{vertex_validator_->primary_label_, vertex_->keys.Keys()};
|
return VertexId{vertex_validator_->primary_label_, vertex_->keys.Keys()};
|
||||||
};
|
};
|
||||||
|
|
||||||
Result<std::vector<LabelId>> VertexAccessor::Labels(View view) const {
|
ShardResult<std::vector<LabelId>> VertexAccessor::Labels(View view) const {
|
||||||
bool exists = true;
|
bool exists = true;
|
||||||
bool deleted = false;
|
bool deleted = false;
|
||||||
std::vector<LabelId> labels;
|
std::vector<LabelId> labels;
|
||||||
@ -267,17 +268,17 @@ Result<std::vector<LabelId>> VertexAccessor::Labels(View view) const {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (!exists) return Error::NONEXISTENT_OBJECT;
|
if (!exists) return SHARD_ERROR(ErrorCode::NONEXISTENT_OBJECT);
|
||||||
if (!for_deleted_ && deleted) return Error::DELETED_OBJECT;
|
if (!for_deleted_ && deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
|
||||||
return std::move(labels);
|
return std::move(labels);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<PropertyValue> VertexAccessor::SetProperty(PropertyId property, const PropertyValue &value) {
|
ShardResult<PropertyValue> VertexAccessor::SetProperty(PropertyId property, const PropertyValue &value) {
|
||||||
utils::MemoryTracker::OutOfMemoryExceptionEnabler oom_exception;
|
utils::MemoryTracker::OutOfMemoryExceptionEnabler oom_exception;
|
||||||
|
|
||||||
if (!PrepareForWrite(transaction_, vertex_)) return Error::SERIALIZATION_ERROR;
|
if (!PrepareForWrite(transaction_, vertex_)) return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR);
|
||||||
|
|
||||||
if (vertex_->deleted) return Error::DELETED_OBJECT;
|
if (vertex_->deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
|
||||||
|
|
||||||
auto current_value = vertex_->properties.GetProperty(property);
|
auto current_value = vertex_->properties.GetProperty(property);
|
||||||
// We could skip setting the value if the previous one is the same to the new
|
// We could skip setting the value if the previous one is the same to the new
|
||||||
@ -294,7 +295,7 @@ Result<PropertyValue> VertexAccessor::SetProperty(PropertyId property, const Pro
|
|||||||
return std::move(current_value);
|
return std::move(current_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<void> VertexAccessor::CheckVertexExistence(View view) const {
|
ShardResult<void> VertexAccessor::CheckVertexExistence(View view) const {
|
||||||
bool exists = true;
|
bool exists = true;
|
||||||
bool deleted = false;
|
bool deleted = false;
|
||||||
Delta *delta = nullptr;
|
Delta *delta = nullptr;
|
||||||
@ -323,27 +324,27 @@ Result<void> VertexAccessor::CheckVertexExistence(View view) const {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (!exists) {
|
if (!exists) {
|
||||||
return Error::NONEXISTENT_OBJECT;
|
return SHARD_ERROR(ErrorCode::NONEXISTENT_OBJECT);
|
||||||
}
|
}
|
||||||
if (!for_deleted_ && deleted) {
|
if (!for_deleted_ && deleted) {
|
||||||
return Error::DELETED_OBJECT;
|
return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
ShardOperationResult<PropertyValue> VertexAccessor::SetPropertyAndValidate(PropertyId property,
|
ShardResult<PropertyValue> VertexAccessor::SetPropertyAndValidate(PropertyId property, const PropertyValue &value) {
|
||||||
const PropertyValue &value) {
|
if (auto maybe_violation_error = vertex_validator_->ValidatePropertyUpdate(property);
|
||||||
if (auto maybe_violation_error = vertex_validator_->ValidatePropertyUpdate(property); maybe_violation_error) {
|
maybe_violation_error.HasError()) {
|
||||||
return {*maybe_violation_error};
|
return {maybe_violation_error.GetError()};
|
||||||
}
|
}
|
||||||
utils::MemoryTracker::OutOfMemoryExceptionEnabler oom_exception;
|
utils::MemoryTracker::OutOfMemoryExceptionEnabler oom_exception;
|
||||||
|
|
||||||
if (!PrepareForWrite(transaction_, vertex_)) {
|
if (!PrepareForWrite(transaction_, vertex_)) {
|
||||||
return {Error::SERIALIZATION_ERROR};
|
return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vertex_->deleted) {
|
if (vertex_->deleted) {
|
||||||
return {Error::DELETED_OBJECT};
|
return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto current_value = vertex_->properties.GetProperty(property);
|
auto current_value = vertex_->properties.GetProperty(property);
|
||||||
@ -361,10 +362,10 @@ ShardOperationResult<PropertyValue> VertexAccessor::SetPropertyAndValidate(Prope
|
|||||||
return std::move(current_value);
|
return std::move(current_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<std::map<PropertyId, PropertyValue>> VertexAccessor::ClearProperties() {
|
ShardResult<std::map<PropertyId, PropertyValue>> VertexAccessor::ClearProperties() {
|
||||||
if (!PrepareForWrite(transaction_, vertex_)) return Error::SERIALIZATION_ERROR;
|
if (!PrepareForWrite(transaction_, vertex_)) return SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR);
|
||||||
|
|
||||||
if (vertex_->deleted) return Error::DELETED_OBJECT;
|
if (vertex_->deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
|
||||||
|
|
||||||
auto properties = vertex_->properties.Properties();
|
auto properties = vertex_->properties.Properties();
|
||||||
for (const auto &property : properties) {
|
for (const auto &property : properties) {
|
||||||
@ -377,7 +378,7 @@ Result<std::map<PropertyId, PropertyValue>> VertexAccessor::ClearProperties() {
|
|||||||
return std::move(properties);
|
return std::move(properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<PropertyValue> VertexAccessor::GetProperty(View view, PropertyId property) const {
|
ShardResult<PropertyValue> VertexAccessor::GetProperty(View view, PropertyId property) const {
|
||||||
return GetProperty(property, view).GetValue();
|
return GetProperty(property, view).GetValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -407,7 +408,7 @@ PropertyValue VertexAccessor::GetPropertyValue(PropertyId property, View view) c
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<PropertyValue> VertexAccessor::GetProperty(PropertyId property, View view) const {
|
ShardResult<PropertyValue> VertexAccessor::GetProperty(PropertyId property, View view) const {
|
||||||
bool exists = true;
|
bool exists = true;
|
||||||
bool deleted = false;
|
bool deleted = false;
|
||||||
PropertyValue value;
|
PropertyValue value;
|
||||||
@ -442,12 +443,12 @@ Result<PropertyValue> VertexAccessor::GetProperty(PropertyId property, View view
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (!exists) return Error::NONEXISTENT_OBJECT;
|
if (!exists) return SHARD_ERROR(ErrorCode::NONEXISTENT_OBJECT);
|
||||||
if (!for_deleted_ && deleted) return Error::DELETED_OBJECT;
|
if (!for_deleted_ && deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
|
||||||
return std::move(value);
|
return std::move(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<std::map<PropertyId, PropertyValue>> VertexAccessor::Properties(View view) const {
|
ShardResult<std::map<PropertyId, PropertyValue>> VertexAccessor::Properties(View view) const {
|
||||||
bool exists = true;
|
bool exists = true;
|
||||||
bool deleted = false;
|
bool deleted = false;
|
||||||
std::map<PropertyId, PropertyValue> properties;
|
std::map<PropertyId, PropertyValue> properties;
|
||||||
@ -492,12 +493,12 @@ Result<std::map<PropertyId, PropertyValue>> VertexAccessor::Properties(View view
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (!exists) return Error::NONEXISTENT_OBJECT;
|
if (!exists) return SHARD_ERROR(ErrorCode::NONEXISTENT_OBJECT);
|
||||||
if (!for_deleted_ && deleted) return Error::DELETED_OBJECT;
|
if (!for_deleted_ && deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
|
||||||
return std::move(properties);
|
return std::move(properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<std::vector<EdgeAccessor>> VertexAccessor::InEdges(View view, const std::vector<EdgeTypeId> &edge_types,
|
ShardResult<std::vector<EdgeAccessor>> VertexAccessor::InEdges(View view, const std::vector<EdgeTypeId> &edge_types,
|
||||||
const VertexId *destination_id) const {
|
const VertexId *destination_id) const {
|
||||||
bool exists = true;
|
bool exists = true;
|
||||||
bool deleted = false;
|
bool deleted = false;
|
||||||
@ -564,8 +565,8 @@ Result<std::vector<EdgeAccessor>> VertexAccessor::InEdges(View view, const std::
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (!exists) return Error::NONEXISTENT_OBJECT;
|
if (!exists) return SHARD_ERROR(ErrorCode::NONEXISTENT_OBJECT);
|
||||||
if (deleted) return Error::DELETED_OBJECT;
|
if (deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
|
||||||
std::vector<EdgeAccessor> ret;
|
std::vector<EdgeAccessor> ret;
|
||||||
if (in_edges.empty()) {
|
if (in_edges.empty()) {
|
||||||
return ret;
|
return ret;
|
||||||
@ -579,7 +580,7 @@ Result<std::vector<EdgeAccessor>> VertexAccessor::InEdges(View view, const std::
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<std::vector<EdgeAccessor>> VertexAccessor::OutEdges(View view, const std::vector<EdgeTypeId> &edge_types,
|
ShardResult<std::vector<EdgeAccessor>> VertexAccessor::OutEdges(View view, const std::vector<EdgeTypeId> &edge_types,
|
||||||
const VertexId *destination_id) const {
|
const VertexId *destination_id) const {
|
||||||
bool exists = true;
|
bool exists = true;
|
||||||
bool deleted = false;
|
bool deleted = false;
|
||||||
@ -644,8 +645,8 @@ Result<std::vector<EdgeAccessor>> VertexAccessor::OutEdges(View view, const std:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (!exists) return Error::NONEXISTENT_OBJECT;
|
if (!exists) return SHARD_ERROR(ErrorCode::NONEXISTENT_OBJECT);
|
||||||
if (deleted) return Error::DELETED_OBJECT;
|
if (deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
|
||||||
std::vector<EdgeAccessor> ret;
|
std::vector<EdgeAccessor> ret;
|
||||||
if (out_edges.empty()) {
|
if (out_edges.empty()) {
|
||||||
return ret;
|
return ret;
|
||||||
@ -659,7 +660,7 @@ Result<std::vector<EdgeAccessor>> VertexAccessor::OutEdges(View view, const std:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<size_t> VertexAccessor::InDegree(View view) const {
|
ShardResult<size_t> VertexAccessor::InDegree(View view) const {
|
||||||
bool exists = true;
|
bool exists = true;
|
||||||
bool deleted = false;
|
bool deleted = false;
|
||||||
size_t degree = 0;
|
size_t degree = 0;
|
||||||
@ -691,12 +692,12 @@ Result<size_t> VertexAccessor::InDegree(View view) const {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (!exists) return Error::NONEXISTENT_OBJECT;
|
if (!exists) return SHARD_ERROR(ErrorCode::NONEXISTENT_OBJECT);
|
||||||
if (!for_deleted_ && deleted) return Error::DELETED_OBJECT;
|
if (!for_deleted_ && deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
|
||||||
return degree;
|
return degree;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<size_t> VertexAccessor::OutDegree(View view) const {
|
ShardResult<size_t> VertexAccessor::OutDegree(View view) const {
|
||||||
bool exists = true;
|
bool exists = true;
|
||||||
bool deleted = false;
|
bool deleted = false;
|
||||||
size_t degree = 0;
|
size_t degree = 0;
|
||||||
@ -728,8 +729,8 @@ Result<size_t> VertexAccessor::OutDegree(View view) const {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (!exists) return Error::NONEXISTENT_OBJECT;
|
if (!exists) return SHARD_ERROR(ErrorCode::NONEXISTENT_OBJECT);
|
||||||
if (!for_deleted_ && deleted) return Error::DELETED_OBJECT;
|
if (!for_deleted_ && deleted) return SHARD_ERROR(ErrorCode::DELETED_OBJECT);
|
||||||
return degree;
|
return degree;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
#include "storage/v3/id_types.hpp"
|
#include "storage/v3/id_types.hpp"
|
||||||
#include "storage/v3/key_store.hpp"
|
#include "storage/v3/key_store.hpp"
|
||||||
#include "storage/v3/result.hpp"
|
#include "storage/v3/result.hpp"
|
||||||
#include "storage/v3/shard_operation_result.hpp"
|
#include "storage/v3/schema_validator.hpp"
|
||||||
#include "storage/v3/transaction.hpp"
|
#include "storage/v3/transaction.hpp"
|
||||||
#include "storage/v3/vertex.hpp"
|
#include "storage/v3/vertex.hpp"
|
||||||
#include "storage/v3/vertex_id.hpp"
|
#include "storage/v3/vertex_id.hpp"
|
||||||
@ -55,61 +55,61 @@ class VertexAccessor final {
|
|||||||
/// `false` is returned if the label already existed, or SchemaViolation
|
/// `false` is returned if the label already existed, or SchemaViolation
|
||||||
/// if adding the label has violated one of the schema constraints.
|
/// if adding the label has violated one of the schema constraints.
|
||||||
/// @throw std::bad_alloc
|
/// @throw std::bad_alloc
|
||||||
ShardOperationResult<bool> AddLabelAndValidate(LabelId label);
|
ShardResult<bool> AddLabelAndValidate(LabelId label);
|
||||||
|
|
||||||
/// Remove a label and return `true` if deletion took place.
|
/// Remove a label and return `true` if deletion took place.
|
||||||
/// `false` is returned if the vertex did not have a label already. or SchemaViolation
|
/// `false` is returned if the vertex did not have a label already. or SchemaViolation
|
||||||
/// if adding the label has violated one of the schema constraints.
|
/// if adding the label has violated one of the schema constraints.
|
||||||
/// @throw std::bad_alloc
|
/// @throw std::bad_alloc
|
||||||
ShardOperationResult<bool> RemoveLabelAndValidate(LabelId label);
|
ShardResult<bool> RemoveLabelAndValidate(LabelId label);
|
||||||
|
|
||||||
Result<bool> HasLabel(View view, LabelId label) const;
|
ShardResult<bool> HasLabel(View view, LabelId label) const;
|
||||||
|
|
||||||
Result<bool> HasLabel(LabelId label, View view) const;
|
ShardResult<bool> HasLabel(LabelId label, View view) const;
|
||||||
|
|
||||||
/// @throw std::bad_alloc
|
/// @throw std::bad_alloc
|
||||||
/// @throw std::length_error if the resulting vector exceeds
|
/// @throw std::length_error if the resulting vector exceeds
|
||||||
/// std::vector::max_size().
|
/// std::vector::max_size().
|
||||||
Result<std::vector<LabelId>> Labels(View view) const;
|
ShardResult<std::vector<LabelId>> Labels(View view) const;
|
||||||
|
|
||||||
Result<LabelId> PrimaryLabel(View view) const;
|
ShardResult<LabelId> PrimaryLabel(View view) const;
|
||||||
|
|
||||||
Result<PrimaryKey> PrimaryKey(View view) const;
|
ShardResult<PrimaryKey> PrimaryKey(View view) const;
|
||||||
|
|
||||||
Result<VertexId> Id(View view) const;
|
ShardResult<VertexId> Id(View view) const;
|
||||||
|
|
||||||
/// Set a property value and return the old value or error.
|
/// Set a property value and return the old value or error.
|
||||||
/// @throw std::bad_alloc
|
/// @throw std::bad_alloc
|
||||||
ShardOperationResult<PropertyValue> SetPropertyAndValidate(PropertyId property, const PropertyValue &value);
|
ShardResult<PropertyValue> SetPropertyAndValidate(PropertyId property, const PropertyValue &value);
|
||||||
|
|
||||||
/// Remove all properties and return the values of the removed properties.
|
/// Remove all properties and return the values of the removed properties.
|
||||||
/// @throw std::bad_alloc
|
/// @throw std::bad_alloc
|
||||||
Result<std::map<PropertyId, PropertyValue>> ClearProperties();
|
ShardResult<std::map<PropertyId, PropertyValue>> ClearProperties();
|
||||||
|
|
||||||
/// @throw std::bad_alloc
|
/// @throw std::bad_alloc
|
||||||
Result<PropertyValue> GetProperty(PropertyId property, View view) const;
|
ShardResult<PropertyValue> GetProperty(PropertyId property, View view) const;
|
||||||
|
|
||||||
// TODO Remove this
|
// TODO Remove this
|
||||||
Result<PropertyValue> GetProperty(View view, PropertyId property) const;
|
ShardResult<PropertyValue> GetProperty(View view, PropertyId property) const;
|
||||||
|
|
||||||
/// @throw std::bad_alloc
|
/// @throw std::bad_alloc
|
||||||
Result<std::map<PropertyId, PropertyValue>> Properties(View view) const;
|
ShardResult<std::map<PropertyId, PropertyValue>> Properties(View view) const;
|
||||||
|
|
||||||
/// @throw std::bad_alloc
|
/// @throw std::bad_alloc
|
||||||
/// @throw std::length_error if the resulting vector exceeds
|
/// @throw std::length_error if the resulting vector exceeds
|
||||||
/// std::vector::max_size().
|
/// std::vector::max_size().
|
||||||
Result<std::vector<EdgeAccessor>> InEdges(View view, const std::vector<EdgeTypeId> &edge_types = {},
|
ShardResult<std::vector<EdgeAccessor>> InEdges(View view, const std::vector<EdgeTypeId> &edge_types = {},
|
||||||
const VertexId *destination_id = nullptr) const;
|
const VertexId *destination_id = nullptr) const;
|
||||||
|
|
||||||
/// @throw std::bad_alloc
|
/// @throw std::bad_alloc
|
||||||
/// @throw std::length_error if the resulting vector exceeds
|
/// @throw std::length_error if the resulting vector exceeds
|
||||||
/// std::vector::max_size().
|
/// std::vector::max_size().
|
||||||
Result<std::vector<EdgeAccessor>> OutEdges(View view, const std::vector<EdgeTypeId> &edge_types = {},
|
ShardResult<std::vector<EdgeAccessor>> OutEdges(View view, const std::vector<EdgeTypeId> &edge_types = {},
|
||||||
const VertexId *destination_id = nullptr) const;
|
const VertexId *destination_id = nullptr) const;
|
||||||
|
|
||||||
Result<size_t> InDegree(View view) const;
|
ShardResult<size_t> InDegree(View view) const;
|
||||||
|
|
||||||
Result<size_t> OutDegree(View view) const;
|
ShardResult<size_t> OutDegree(View view) const;
|
||||||
|
|
||||||
const SchemaValidator *GetSchemaValidator() const;
|
const SchemaValidator *GetSchemaValidator() const;
|
||||||
|
|
||||||
@ -122,20 +122,20 @@ class VertexAccessor final {
|
|||||||
/// Add a label and return `true` if insertion took place.
|
/// Add a label and return `true` if insertion took place.
|
||||||
/// `false` is returned if the label already existed.
|
/// `false` is returned if the label already existed.
|
||||||
/// @throw std::bad_alloc
|
/// @throw std::bad_alloc
|
||||||
Result<bool> AddLabel(LabelId label);
|
ShardResult<bool> AddLabel(LabelId label);
|
||||||
|
|
||||||
/// Remove a label and return `true` if deletion took place.
|
/// Remove a label and return `true` if deletion took place.
|
||||||
/// `false` is returned if the vertex did not have a label already.
|
/// `false` is returned if the vertex did not have a label already.
|
||||||
/// @throw std::bad_alloc
|
/// @throw std::bad_alloc
|
||||||
Result<bool> RemoveLabel(LabelId label);
|
ShardResult<bool> RemoveLabel(LabelId label);
|
||||||
|
|
||||||
/// Set a property value and return the old value.
|
/// Set a property value and return the old value.
|
||||||
/// @throw std::bad_alloc
|
/// @throw std::bad_alloc
|
||||||
Result<PropertyValue> SetProperty(PropertyId property, const PropertyValue &value);
|
ShardResult<PropertyValue> SetProperty(PropertyId property, const PropertyValue &value);
|
||||||
|
|
||||||
PropertyValue GetPropertyValue(PropertyId property, View view) const;
|
PropertyValue GetPropertyValue(PropertyId property, View view) const;
|
||||||
|
|
||||||
Result<void> CheckVertexExistence(View view) const;
|
ShardResult<void> CheckVertexExistence(View view) const;
|
||||||
|
|
||||||
Vertex *vertex_;
|
Vertex *vertex_;
|
||||||
Transaction *transaction_;
|
Transaction *transaction_;
|
||||||
|
@ -11,16 +11,9 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <variant>
|
namespace memgraph::utils {
|
||||||
|
|
||||||
#include "storage/v3/result.hpp"
|
template <typename>
|
||||||
#include "storage/v3/schema_validator.hpp"
|
constexpr auto kAlwaysFalse{false};
|
||||||
|
|
||||||
namespace memgraph::storage::v3 {
|
} // namespace memgraph::utils
|
||||||
|
|
||||||
using ResultErrorType = std::variant<SchemaViolation, Error>;
|
|
||||||
|
|
||||||
template <typename TValue>
|
|
||||||
using ShardOperationResult = utils::BasicResult<ResultErrorType, TValue>;
|
|
||||||
|
|
||||||
} // namespace memgraph::storage::v3
|
|
@ -137,7 +137,7 @@ void Commit(ShardClient &client, const coordinator::Hlc &transaction_timestamp)
|
|||||||
|
|
||||||
auto write_response_result = write_res.GetValue();
|
auto write_response_result = write_res.GetValue();
|
||||||
auto write_response = std::get<msgs::CommitResponse>(write_response_result);
|
auto write_response = std::get<msgs::CommitResponse>(write_response_result);
|
||||||
MG_ASSERT(write_response.success, "Commit expected to be successful, but it is failed");
|
MG_ASSERT(!write_response.error.has_value(), "Commit expected to be successful, but it is failed");
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -156,7 +156,7 @@ bool AttemptToCreateVertex(ShardClient &client, int64_t value) {
|
|||||||
create_req.transaction_id.logical_id = GetTransactionId();
|
create_req.transaction_id.logical_id = GetTransactionId();
|
||||||
|
|
||||||
auto write_res = client.SendWriteRequest(create_req);
|
auto write_res = client.SendWriteRequest(create_req);
|
||||||
MG_ASSERT(write_res.HasValue() && std::get<msgs::CreateVerticesResponse>(write_res.GetValue()).success,
|
MG_ASSERT(write_res.HasValue() && !std::get<msgs::CreateVerticesResponse>(write_res.GetValue()).error.has_value(),
|
||||||
"Unexpected failure");
|
"Unexpected failure");
|
||||||
|
|
||||||
Commit(client, create_req.transaction_id);
|
Commit(client, create_req.transaction_id);
|
||||||
@ -179,23 +179,26 @@ bool AttemptToDeleteVertex(ShardClient &client, int64_t value) {
|
|||||||
auto write_response = std::get<msgs::DeleteVerticesResponse>(write_response_result);
|
auto write_response = std::get<msgs::DeleteVerticesResponse>(write_response_result);
|
||||||
|
|
||||||
Commit(client, delete_req.transaction_id);
|
Commit(client, delete_req.transaction_id);
|
||||||
return write_response.success;
|
return !write_response.error.has_value();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AttemptToUpdateVertex(ShardClient &client, int64_t value) {
|
bool AttemptToUpdateVertex(ShardClient &client, int64_t vertex_primary_key, std::vector<LabelId> add_labels = {},
|
||||||
auto vertex_id = GetValuePrimaryKeysWithValue(value)[0];
|
std::vector<LabelId> remove_labels = {}) {
|
||||||
|
auto vertex_id = GetValuePrimaryKeysWithValue(vertex_primary_key)[0];
|
||||||
|
|
||||||
std::vector<std::pair<PropertyId, msgs::Value>> property_updates;
|
std::vector<std::pair<PropertyId, msgs::Value>> property_updates;
|
||||||
auto property_update = std::make_pair(PropertyId::FromUint(5), msgs::Value(static_cast<int64_t>(10000)));
|
auto property_update = std::make_pair(PropertyId::FromUint(5), msgs::Value(static_cast<int64_t>(10000)));
|
||||||
|
|
||||||
auto vertex_prop = msgs::UpdateVertexProp{};
|
msgs::UpdateVertex update_vertex;
|
||||||
vertex_prop.primary_key = vertex_id;
|
update_vertex.primary_key = vertex_id;
|
||||||
vertex_prop.property_updates = {property_update};
|
update_vertex.property_updates = {property_update};
|
||||||
|
update_vertex.add_labels = add_labels;
|
||||||
|
update_vertex.remove_labels = remove_labels;
|
||||||
|
|
||||||
auto update_req = msgs::UpdateVerticesRequest{};
|
msgs::UpdateVerticesRequest update_req;
|
||||||
update_req.transaction_id.logical_id = GetTransactionId();
|
update_req.transaction_id.logical_id = GetTransactionId();
|
||||||
update_req.new_properties = {vertex_prop};
|
update_req.update_vertices = {update_vertex};
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
auto write_res = client.SendWriteRequest(update_req);
|
auto write_res = client.SendWriteRequest(update_req);
|
||||||
@ -207,7 +210,38 @@ bool AttemptToUpdateVertex(ShardClient &client, int64_t value) {
|
|||||||
auto write_response = std::get<msgs::UpdateVerticesResponse>(write_response_result);
|
auto write_response = std::get<msgs::UpdateVerticesResponse>(write_response_result);
|
||||||
|
|
||||||
Commit(client, update_req.transaction_id);
|
Commit(client, update_req.transaction_id);
|
||||||
return write_response.success;
|
return !write_response.error.has_value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AttemptToRemoveVertexProperty(ShardClient &client, int64_t primary_key, std::vector<LabelId> add_labels = {},
|
||||||
|
std::vector<LabelId> remove_labels = {}) {
|
||||||
|
auto vertex_id = GetValuePrimaryKeysWithValue(primary_key)[0];
|
||||||
|
|
||||||
|
std::vector<std::pair<PropertyId, msgs::Value>> property_updates;
|
||||||
|
auto property_update = std::make_pair(PropertyId::FromUint(5), msgs::Value());
|
||||||
|
|
||||||
|
msgs::UpdateVertex update_vertex;
|
||||||
|
update_vertex.primary_key = vertex_id;
|
||||||
|
update_vertex.property_updates = {property_update};
|
||||||
|
update_vertex.add_labels = add_labels;
|
||||||
|
update_vertex.remove_labels = remove_labels;
|
||||||
|
|
||||||
|
msgs::UpdateVerticesRequest update_req;
|
||||||
|
update_req.transaction_id.logical_id = GetTransactionId();
|
||||||
|
update_req.update_vertices = {update_vertex};
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
auto write_res = client.SendWriteRequest(update_req);
|
||||||
|
if (write_res.HasError()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto write_response_result = write_res.GetValue();
|
||||||
|
auto write_response = std::get<msgs::UpdateVerticesResponse>(write_response_result);
|
||||||
|
|
||||||
|
Commit(client, update_req.transaction_id);
|
||||||
|
return !write_response.error.has_value();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,7 +278,7 @@ bool AttemptToAddEdge(ShardClient &client, int64_t value_of_vertex_1, int64_t va
|
|||||||
|
|
||||||
Commit(client, create_req.transaction_id);
|
Commit(client, create_req.transaction_id);
|
||||||
|
|
||||||
return write_response.success;
|
return !write_response.error.has_value();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -276,7 +310,7 @@ bool AttemptToAddEdgeWithProperties(ShardClient &client, int64_t value_of_vertex
|
|||||||
create_req.transaction_id.logical_id = GetTransactionId();
|
create_req.transaction_id.logical_id = GetTransactionId();
|
||||||
|
|
||||||
auto write_res = client.SendWriteRequest(create_req);
|
auto write_res = client.SendWriteRequest(create_req);
|
||||||
MG_ASSERT(write_res.HasValue() && std::get<msgs::CreateExpandResponse>(write_res.GetValue()).success,
|
MG_ASSERT(write_res.HasValue() && !std::get<msgs::CreateExpandResponse>(write_res.GetValue()).error.has_value(),
|
||||||
"Unexpected failure");
|
"Unexpected failure");
|
||||||
|
|
||||||
Commit(client, create_req.transaction_id);
|
Commit(client, create_req.transaction_id);
|
||||||
@ -316,7 +350,7 @@ bool AttemptToDeleteEdge(ShardClient &client, int64_t value_of_vertex_1, int64_t
|
|||||||
auto write_response = std::get<msgs::DeleteEdgesResponse>(write_response_result);
|
auto write_response = std::get<msgs::DeleteEdgesResponse>(write_response_result);
|
||||||
|
|
||||||
Commit(client, delete_req.transaction_id);
|
Commit(client, delete_req.transaction_id);
|
||||||
return write_response.success;
|
return !write_response.error.has_value();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -356,7 +390,7 @@ bool AttemptToUpdateEdge(ShardClient &client, int64_t value_of_vertex_1, int64_t
|
|||||||
auto write_response = std::get<msgs::UpdateEdgesResponse>(write_response_result);
|
auto write_response = std::get<msgs::UpdateEdgesResponse>(write_response_result);
|
||||||
|
|
||||||
Commit(client, update_req.transaction_id);
|
Commit(client, update_req.transaction_id);
|
||||||
return write_response.success;
|
return !write_response.error.has_value();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -379,7 +413,7 @@ std::tuple<size_t, std::optional<msgs::VertexId>> AttemptToScanAllWithoutBatchLi
|
|||||||
auto write_response_result = read_res.GetValue();
|
auto write_response_result = read_res.GetValue();
|
||||||
auto write_response = std::get<msgs::ScanVerticesResponse>(write_response_result);
|
auto write_response = std::get<msgs::ScanVerticesResponse>(write_response_result);
|
||||||
|
|
||||||
MG_ASSERT(write_response.success);
|
MG_ASSERT(write_response.error == std::nullopt);
|
||||||
|
|
||||||
return {write_response.results.size(), write_response.next_start_id};
|
return {write_response.results.size(), write_response.next_start_id};
|
||||||
}
|
}
|
||||||
@ -405,7 +439,7 @@ std::tuple<size_t, std::optional<msgs::VertexId>> AttemptToScanAllWithBatchLimit
|
|||||||
auto write_response_result = read_res.GetValue();
|
auto write_response_result = read_res.GetValue();
|
||||||
auto write_response = std::get<msgs::ScanVerticesResponse>(write_response_result);
|
auto write_response = std::get<msgs::ScanVerticesResponse>(write_response_result);
|
||||||
|
|
||||||
MG_ASSERT(write_response.success);
|
MG_ASSERT(!write_response.error.has_value());
|
||||||
|
|
||||||
return {write_response.results.size(), write_response.next_start_id};
|
return {write_response.results.size(), write_response.next_start_id};
|
||||||
}
|
}
|
||||||
@ -439,7 +473,7 @@ std::tuple<size_t, std::optional<msgs::VertexId>> AttemptToScanAllWithExpression
|
|||||||
auto write_response_result = read_res.GetValue();
|
auto write_response_result = read_res.GetValue();
|
||||||
auto write_response = std::get<msgs::ScanVerticesResponse>(write_response_result);
|
auto write_response = std::get<msgs::ScanVerticesResponse>(write_response_result);
|
||||||
|
|
||||||
MG_ASSERT(write_response.success);
|
MG_ASSERT(!write_response.error.has_value());
|
||||||
MG_ASSERT(!write_response.results.empty(), "There are no results!");
|
MG_ASSERT(!write_response.results.empty(), "There are no results!");
|
||||||
MG_ASSERT(write_response.results[0].evaluated_vertex_expressions[0].int_v == 4);
|
MG_ASSERT(write_response.results[0].evaluated_vertex_expressions[0].int_v == 4);
|
||||||
return {write_response.results.size(), write_response.next_start_id};
|
return {write_response.results.size(), write_response.next_start_id};
|
||||||
@ -464,7 +498,7 @@ void AttemptToScanAllWithOrderByOnPrimaryProperty(ShardClient &client, msgs::Ver
|
|||||||
auto write_response_result = read_res.GetValue();
|
auto write_response_result = read_res.GetValue();
|
||||||
auto write_response = std::get<msgs::ScanVerticesResponse>(write_response_result);
|
auto write_response = std::get<msgs::ScanVerticesResponse>(write_response_result);
|
||||||
|
|
||||||
MG_ASSERT(write_response.success);
|
MG_ASSERT(!write_response.error.has_value());
|
||||||
MG_ASSERT(write_response.results.size() == 5, "Expecting 5 results!");
|
MG_ASSERT(write_response.results.size() == 5, "Expecting 5 results!");
|
||||||
for (int64_t i{0}; i < 5; ++i) {
|
for (int64_t i{0}; i < 5; ++i) {
|
||||||
const auto expected_primary_key = std::vector{msgs::Value(1023 - i)};
|
const auto expected_primary_key = std::vector{msgs::Value(1023 - i)};
|
||||||
@ -494,7 +528,7 @@ void AttemptToScanAllWithOrderByOnSecondaryProperty(ShardClient &client, msgs::V
|
|||||||
auto write_response_result = read_res.GetValue();
|
auto write_response_result = read_res.GetValue();
|
||||||
auto write_response = std::get<msgs::ScanVerticesResponse>(write_response_result);
|
auto write_response = std::get<msgs::ScanVerticesResponse>(write_response_result);
|
||||||
|
|
||||||
MG_ASSERT(write_response.success);
|
MG_ASSERT(!write_response.error.has_value());
|
||||||
MG_ASSERT(write_response.results.size() == 5, "Expecting 5 results!");
|
MG_ASSERT(write_response.results.size() == 5, "Expecting 5 results!");
|
||||||
for (int64_t i{0}; i < 5; ++i) {
|
for (int64_t i{0}; i < 5; ++i) {
|
||||||
const auto expected_prop4 = std::vector{msgs::Value(1023 - i)};
|
const auto expected_prop4 = std::vector{msgs::Value(1023 - i)};
|
||||||
@ -531,7 +565,8 @@ void AttemptToExpandOneWithWrongEdgeType(ShardClient &client, uint64_t src_verte
|
|||||||
std::optional<std::vector<PropertyId>> edge_properties = {};
|
std::optional<std::vector<PropertyId>> edge_properties = {};
|
||||||
|
|
||||||
std::vector<std::string> expressions;
|
std::vector<std::string> expressions;
|
||||||
std::optional<std::vector<msgs::OrderBy>> order_by = {};
|
std::vector<msgs::OrderBy> order_by_vertices = {};
|
||||||
|
std::vector<msgs::OrderBy> order_by_edges = {};
|
||||||
std::optional<size_t> limit = {};
|
std::optional<size_t> limit = {};
|
||||||
std::vector<std::string> filter = {};
|
std::vector<std::string> filter = {};
|
||||||
|
|
||||||
@ -543,7 +578,8 @@ void AttemptToExpandOneWithWrongEdgeType(ShardClient &client, uint64_t src_verte
|
|||||||
expand_one_req.vertex_expressions = expressions;
|
expand_one_req.vertex_expressions = expressions;
|
||||||
expand_one_req.filters = filter;
|
expand_one_req.filters = filter;
|
||||||
expand_one_req.limit = limit;
|
expand_one_req.limit = limit;
|
||||||
expand_one_req.order_by = order_by;
|
expand_one_req.order_by_vertices = order_by_vertices;
|
||||||
|
expand_one_req.order_by_edges = order_by_edges;
|
||||||
expand_one_req.src_vertex_properties = src_vertex_properties;
|
expand_one_req.src_vertex_properties = src_vertex_properties;
|
||||||
expand_one_req.src_vertices = {src_vertex};
|
expand_one_req.src_vertices = {src_vertex};
|
||||||
expand_one_req.transaction_id.logical_id = GetTransactionId();
|
expand_one_req.transaction_id.logical_id = GetTransactionId();
|
||||||
@ -586,7 +622,8 @@ void AttemptToExpandOneSimple(ShardClient &client, uint64_t src_vertex_val, Edge
|
|||||||
std::optional<std::vector<PropertyId>> edge_properties = {};
|
std::optional<std::vector<PropertyId>> edge_properties = {};
|
||||||
|
|
||||||
std::vector<std::string> expressions;
|
std::vector<std::string> expressions;
|
||||||
std::optional<std::vector<msgs::OrderBy>> order_by = {};
|
std::vector<msgs::OrderBy> order_by_vertices = {};
|
||||||
|
std::vector<msgs::OrderBy> order_by_edges = {};
|
||||||
std::optional<size_t> limit = {};
|
std::optional<size_t> limit = {};
|
||||||
std::vector<std::string> filter = {};
|
std::vector<std::string> filter = {};
|
||||||
|
|
||||||
@ -598,7 +635,8 @@ void AttemptToExpandOneSimple(ShardClient &client, uint64_t src_vertex_val, Edge
|
|||||||
expand_one_req.vertex_expressions = expressions;
|
expand_one_req.vertex_expressions = expressions;
|
||||||
expand_one_req.filters = filter;
|
expand_one_req.filters = filter;
|
||||||
expand_one_req.limit = limit;
|
expand_one_req.limit = limit;
|
||||||
expand_one_req.order_by = order_by;
|
expand_one_req.order_by_vertices = order_by_vertices;
|
||||||
|
expand_one_req.order_by_edges = order_by_edges;
|
||||||
expand_one_req.src_vertex_properties = src_vertex_properties;
|
expand_one_req.src_vertex_properties = src_vertex_properties;
|
||||||
expand_one_req.src_vertices = {src_vertex};
|
expand_one_req.src_vertices = {src_vertex};
|
||||||
expand_one_req.transaction_id.logical_id = GetTransactionId();
|
expand_one_req.transaction_id.logical_id = GetTransactionId();
|
||||||
@ -642,7 +680,8 @@ void AttemptToExpandOneWithUniqueEdges(ShardClient &client, uint64_t src_vertex_
|
|||||||
std::optional<std::vector<PropertyId>> edge_properties = {};
|
std::optional<std::vector<PropertyId>> edge_properties = {};
|
||||||
|
|
||||||
std::vector<std::string> expressions;
|
std::vector<std::string> expressions;
|
||||||
std::optional<std::vector<msgs::OrderBy>> order_by = {};
|
std::vector<msgs::OrderBy> order_by_vertices = {};
|
||||||
|
std::vector<msgs::OrderBy> order_by_edges = {};
|
||||||
std::optional<size_t> limit = {};
|
std::optional<size_t> limit = {};
|
||||||
std::vector<std::string> filter = {};
|
std::vector<std::string> filter = {};
|
||||||
|
|
||||||
@ -654,7 +693,8 @@ void AttemptToExpandOneWithUniqueEdges(ShardClient &client, uint64_t src_vertex_
|
|||||||
expand_one_req.vertex_expressions = expressions;
|
expand_one_req.vertex_expressions = expressions;
|
||||||
expand_one_req.filters = filter;
|
expand_one_req.filters = filter;
|
||||||
expand_one_req.limit = limit;
|
expand_one_req.limit = limit;
|
||||||
expand_one_req.order_by = order_by;
|
expand_one_req.order_by_vertices = order_by_vertices;
|
||||||
|
expand_one_req.order_by_edges = order_by_edges;
|
||||||
expand_one_req.src_vertex_properties = src_vertex_properties;
|
expand_one_req.src_vertex_properties = src_vertex_properties;
|
||||||
expand_one_req.src_vertices = {src_vertex};
|
expand_one_req.src_vertices = {src_vertex};
|
||||||
expand_one_req.only_unique_neighbor_rows = true;
|
expand_one_req.only_unique_neighbor_rows = true;
|
||||||
@ -680,6 +720,88 @@ void AttemptToExpandOneWithUniqueEdges(ShardClient &client, uint64_t src_vertex_
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AttemptToExpandOneLimitAndOrderBy(ShardClient &client, uint64_t src_vertex_val, uint64_t other_src_vertex_val,
|
||||||
|
EdgeTypeId edge_type_id) {
|
||||||
|
// Source vertex
|
||||||
|
msgs::Label label = {.id = get_primary_label()};
|
||||||
|
auto src_vertex = std::make_pair(label, GetPrimaryKey(src_vertex_val));
|
||||||
|
auto other_src_vertex = std::make_pair(label, GetPrimaryKey(other_src_vertex_val));
|
||||||
|
|
||||||
|
// Edge type
|
||||||
|
auto edge_type = msgs::EdgeType{};
|
||||||
|
edge_type.id = edge_type_id;
|
||||||
|
|
||||||
|
// Edge direction
|
||||||
|
auto edge_direction = msgs::EdgeDirection::OUT;
|
||||||
|
|
||||||
|
// Source Vertex properties to look for
|
||||||
|
std::optional<std::vector<PropertyId>> src_vertex_properties = {};
|
||||||
|
|
||||||
|
// Edge properties to look for
|
||||||
|
std::optional<std::vector<PropertyId>> edge_properties = {};
|
||||||
|
|
||||||
|
std::vector<msgs::OrderBy> order_by_vertices = {
|
||||||
|
{msgs::Expression{"MG_SYMBOL_NODE.prop1"}, msgs::OrderingDirection::ASCENDING}};
|
||||||
|
std::vector<msgs::OrderBy> order_by_edges = {
|
||||||
|
{msgs::Expression{"MG_SYMBOL_EDGE.prop4"}, msgs::OrderingDirection::DESCENDING}};
|
||||||
|
|
||||||
|
size_t limit = 1;
|
||||||
|
std::vector<std::string> filters = {"MG_SYMBOL_NODE.prop1 != -1"};
|
||||||
|
|
||||||
|
msgs::ExpandOneRequest expand_one_req{};
|
||||||
|
|
||||||
|
expand_one_req.direction = edge_direction;
|
||||||
|
expand_one_req.edge_properties = edge_properties;
|
||||||
|
expand_one_req.edge_types = {edge_type};
|
||||||
|
expand_one_req.filters = filters;
|
||||||
|
expand_one_req.limit = limit;
|
||||||
|
expand_one_req.order_by_vertices = order_by_vertices;
|
||||||
|
expand_one_req.order_by_edges = order_by_edges;
|
||||||
|
expand_one_req.src_vertex_properties = src_vertex_properties;
|
||||||
|
expand_one_req.src_vertices = {src_vertex, other_src_vertex};
|
||||||
|
expand_one_req.transaction_id.logical_id = GetTransactionId();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
auto read_res = client.SendReadRequest(expand_one_req);
|
||||||
|
if (read_res.HasError()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto write_response_result = read_res.GetValue();
|
||||||
|
auto write_response = std::get<msgs::ExpandOneResponse>(write_response_result);
|
||||||
|
|
||||||
|
// We check that we do not have more results than the limit. Based on the data in the graph, we know that we should
|
||||||
|
// receive exactly limit responses.
|
||||||
|
auto expected_number_of_rows = std::min(expand_one_req.src_vertices.size(), limit);
|
||||||
|
MG_ASSERT(expected_number_of_rows == 1);
|
||||||
|
MG_ASSERT(write_response.result.size() == expected_number_of_rows);
|
||||||
|
|
||||||
|
// We know there are 1 out-going edges from V1->V2
|
||||||
|
// We know there are 10 out-going edges from V2->V3
|
||||||
|
// Since we sort on prop1 and limit 1, we will have a single response
|
||||||
|
// with two edges corresponding to V1->V2 and V1->V3
|
||||||
|
const auto expected_number_of_edges = 2;
|
||||||
|
MG_ASSERT(write_response.result[0].out_edges_with_all_properties.size() == expected_number_of_edges);
|
||||||
|
MG_ASSERT(write_response.result[0]
|
||||||
|
.out_edges_with_specific_properties.empty()); // We are not asking for specific properties
|
||||||
|
|
||||||
|
// We also check that the vertices are ordered by prop1 DESC
|
||||||
|
|
||||||
|
auto is_sorted = std::is_sorted(write_response.result.cbegin(), write_response.result.cend(),
|
||||||
|
[](const auto &vertex, const auto &other_vertex) {
|
||||||
|
const auto primary_key = vertex.src_vertex.id.second;
|
||||||
|
const auto other_primary_key = other_vertex.src_vertex.id.second;
|
||||||
|
|
||||||
|
MG_ASSERT(primary_key.size() == 1);
|
||||||
|
MG_ASSERT(other_primary_key.size() == 1);
|
||||||
|
return primary_key[0].int_v > other_primary_key[0].int_v;
|
||||||
|
});
|
||||||
|
|
||||||
|
MG_ASSERT(is_sorted);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AttemptToExpandOneWithSpecifiedSrcVertexProperties(ShardClient &client, uint64_t src_vertex_val,
|
void AttemptToExpandOneWithSpecifiedSrcVertexProperties(ShardClient &client, uint64_t src_vertex_val,
|
||||||
EdgeTypeId edge_type_id) {
|
EdgeTypeId edge_type_id) {
|
||||||
// Source vertex
|
// Source vertex
|
||||||
@ -701,7 +823,8 @@ void AttemptToExpandOneWithSpecifiedSrcVertexProperties(ShardClient &client, uin
|
|||||||
std::optional<std::vector<PropertyId>> edge_properties = {};
|
std::optional<std::vector<PropertyId>> edge_properties = {};
|
||||||
|
|
||||||
std::vector<std::string> expressions;
|
std::vector<std::string> expressions;
|
||||||
std::optional<std::vector<msgs::OrderBy>> order_by = {};
|
std::vector<msgs::OrderBy> order_by_vertices = {};
|
||||||
|
std::vector<msgs::OrderBy> order_by_edges = {};
|
||||||
std::optional<size_t> limit = {};
|
std::optional<size_t> limit = {};
|
||||||
std::vector<std::string> filter = {};
|
std::vector<std::string> filter = {};
|
||||||
|
|
||||||
@ -713,7 +836,8 @@ void AttemptToExpandOneWithSpecifiedSrcVertexProperties(ShardClient &client, uin
|
|||||||
expand_one_req.vertex_expressions = expressions;
|
expand_one_req.vertex_expressions = expressions;
|
||||||
expand_one_req.filters = filter;
|
expand_one_req.filters = filter;
|
||||||
expand_one_req.limit = limit;
|
expand_one_req.limit = limit;
|
||||||
expand_one_req.order_by = order_by;
|
expand_one_req.order_by_vertices = order_by_vertices;
|
||||||
|
expand_one_req.order_by_edges = order_by_edges;
|
||||||
expand_one_req.src_vertex_properties = src_vertex_properties;
|
expand_one_req.src_vertex_properties = src_vertex_properties;
|
||||||
expand_one_req.src_vertices = {src_vertex};
|
expand_one_req.src_vertices = {src_vertex};
|
||||||
expand_one_req.transaction_id.logical_id = GetTransactionId();
|
expand_one_req.transaction_id.logical_id = GetTransactionId();
|
||||||
@ -761,7 +885,8 @@ void AttemptToExpandOneWithSpecifiedEdgeProperties(ShardClient &client, uint64_t
|
|||||||
std::optional<std::vector<PropertyId>> edge_properties = {specified_edge_prop};
|
std::optional<std::vector<PropertyId>> edge_properties = {specified_edge_prop};
|
||||||
|
|
||||||
std::vector<std::string> expressions;
|
std::vector<std::string> expressions;
|
||||||
std::optional<std::vector<msgs::OrderBy>> order_by = {};
|
std::vector<msgs::OrderBy> order_by_vertices = {};
|
||||||
|
std::vector<msgs::OrderBy> order_by_edges = {};
|
||||||
std::optional<size_t> limit = {};
|
std::optional<size_t> limit = {};
|
||||||
std::vector<std::string> filter = {};
|
std::vector<std::string> filter = {};
|
||||||
|
|
||||||
@ -773,7 +898,8 @@ void AttemptToExpandOneWithSpecifiedEdgeProperties(ShardClient &client, uint64_t
|
|||||||
expand_one_req.vertex_expressions = expressions;
|
expand_one_req.vertex_expressions = expressions;
|
||||||
expand_one_req.filters = filter;
|
expand_one_req.filters = filter;
|
||||||
expand_one_req.limit = limit;
|
expand_one_req.limit = limit;
|
||||||
expand_one_req.order_by = order_by;
|
expand_one_req.order_by_vertices = order_by_vertices;
|
||||||
|
expand_one_req.order_by_edges = order_by_edges;
|
||||||
expand_one_req.src_vertex_properties = src_vertex_properties;
|
expand_one_req.src_vertex_properties = src_vertex_properties;
|
||||||
expand_one_req.src_vertices = {src_vertex};
|
expand_one_req.src_vertices = {src_vertex};
|
||||||
expand_one_req.transaction_id.logical_id = GetTransactionId();
|
expand_one_req.transaction_id.logical_id = GetTransactionId();
|
||||||
@ -820,7 +946,8 @@ void AttemptToExpandOneWithFilters(ShardClient &client, uint64_t src_vertex_val,
|
|||||||
std::optional<std::vector<PropertyId>> edge_properties = {};
|
std::optional<std::vector<PropertyId>> edge_properties = {};
|
||||||
|
|
||||||
std::vector<std::string> expressions;
|
std::vector<std::string> expressions;
|
||||||
std::optional<std::vector<msgs::OrderBy>> order_by = {};
|
std::vector<msgs::OrderBy> order_by_vertices = {};
|
||||||
|
std::vector<msgs::OrderBy> order_by_edges = {};
|
||||||
std::optional<size_t> limit = {};
|
std::optional<size_t> limit = {};
|
||||||
std::vector<std::string> filter = {};
|
std::vector<std::string> filter = {};
|
||||||
|
|
||||||
@ -832,7 +959,8 @@ void AttemptToExpandOneWithFilters(ShardClient &client, uint64_t src_vertex_val,
|
|||||||
expand_one_req.vertex_expressions = expressions;
|
expand_one_req.vertex_expressions = expressions;
|
||||||
expand_one_req.filters = {filter_expr1};
|
expand_one_req.filters = {filter_expr1};
|
||||||
expand_one_req.limit = limit;
|
expand_one_req.limit = limit;
|
||||||
expand_one_req.order_by = order_by;
|
expand_one_req.order_by_vertices = order_by_vertices;
|
||||||
|
expand_one_req.order_by_edges = order_by_edges;
|
||||||
expand_one_req.src_vertex_properties = src_vertex_properties;
|
expand_one_req.src_vertex_properties = src_vertex_properties;
|
||||||
expand_one_req.src_vertices = {src_vertex};
|
expand_one_req.src_vertices = {src_vertex};
|
||||||
expand_one_req.transaction_id.logical_id = GetTransactionId();
|
expand_one_req.transaction_id.logical_id = GetTransactionId();
|
||||||
@ -872,7 +1000,9 @@ void TestCreateAndUpdateVertices(ShardClient &client) {
|
|||||||
auto unique_prop_val = GetUniqueInteger();
|
auto unique_prop_val = GetUniqueInteger();
|
||||||
|
|
||||||
MG_ASSERT(AttemptToCreateVertex(client, unique_prop_val));
|
MG_ASSERT(AttemptToCreateVertex(client, unique_prop_val));
|
||||||
MG_ASSERT(AttemptToUpdateVertex(client, unique_prop_val));
|
MG_ASSERT(AttemptToUpdateVertex(client, unique_prop_val, {LabelId::FromInt(3)}, {}));
|
||||||
|
MG_ASSERT(AttemptToUpdateVertex(client, unique_prop_val, {}, {LabelId::FromInt(3)}));
|
||||||
|
MG_ASSERT(AttemptToRemoveVertexProperty(client, unique_prop_val));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestCreateEdge(ShardClient &client) {
|
void TestCreateEdge(ShardClient &client) {
|
||||||
@ -1021,6 +1151,9 @@ void TestExpandOneGraphOne(ShardClient &client) {
|
|||||||
auto edge_prop_id = GetUniqueInteger();
|
auto edge_prop_id = GetUniqueInteger();
|
||||||
auto edge_prop_val = GetUniqueInteger();
|
auto edge_prop_val = GetUniqueInteger();
|
||||||
|
|
||||||
|
std::vector<uint64_t> edges_ids(10);
|
||||||
|
std::generate(edges_ids.begin(), edges_ids.end(), GetUniqueInteger);
|
||||||
|
|
||||||
// (V1)-[edge_type_id]->(V2)
|
// (V1)-[edge_type_id]->(V2)
|
||||||
MG_ASSERT(AttemptToAddEdgeWithProperties(client, unique_prop_val_1, unique_prop_val_2, edge_gid_1, edge_prop_id,
|
MG_ASSERT(AttemptToAddEdgeWithProperties(client, unique_prop_val_1, unique_prop_val_2, edge_gid_1, edge_prop_id,
|
||||||
edge_prop_val, {edge_type_id}));
|
edge_prop_val, {edge_type_id}));
|
||||||
@ -1028,7 +1161,14 @@ void TestExpandOneGraphOne(ShardClient &client) {
|
|||||||
MG_ASSERT(AttemptToAddEdgeWithProperties(client, unique_prop_val_1, unique_prop_val_3, edge_gid_2, edge_prop_id,
|
MG_ASSERT(AttemptToAddEdgeWithProperties(client, unique_prop_val_1, unique_prop_val_3, edge_gid_2, edge_prop_id,
|
||||||
edge_prop_val, {edge_type_id}));
|
edge_prop_val, {edge_type_id}));
|
||||||
|
|
||||||
|
// (V2)-[edge_type_id]->(V3) x 10
|
||||||
|
std::for_each(edges_ids.begin(), edges_ids.end(), [&](const auto &edge_id) {
|
||||||
|
MG_ASSERT(AttemptToAddEdgeWithProperties(client, unique_prop_val_2, unique_prop_val_3, edge_id, edge_prop_id,
|
||||||
|
edge_prop_val, {edge_type_id}));
|
||||||
|
});
|
||||||
|
|
||||||
AttemptToExpandOneSimple(client, unique_prop_val_1, edge_type_id);
|
AttemptToExpandOneSimple(client, unique_prop_val_1, edge_type_id);
|
||||||
|
AttemptToExpandOneLimitAndOrderBy(client, unique_prop_val_1, unique_prop_val_2, edge_type_id);
|
||||||
AttemptToExpandOneWithWrongEdgeType(client, unique_prop_val_1, wrong_edge_type_id);
|
AttemptToExpandOneWithWrongEdgeType(client, unique_prop_val_1, wrong_edge_type_id);
|
||||||
AttemptToExpandOneWithSpecifiedSrcVertexProperties(client, unique_prop_val_1, edge_type_id);
|
AttemptToExpandOneWithSpecifiedSrcVertexProperties(client, unique_prop_val_1, edge_type_id);
|
||||||
AttemptToExpandOneWithSpecifiedEdgeProperties(client, unique_prop_val_1, edge_type_id, edge_prop_id);
|
AttemptToExpandOneWithSpecifiedEdgeProperties(client, unique_prop_val_1, edge_type_id, edge_prop_id);
|
||||||
|
@ -177,7 +177,7 @@ void ExecuteOp(msgs::ShardRequestManager<SimulatorTransport> &shard_request_mana
|
|||||||
auto result = shard_request_manager.Request(state, std::move(new_vertices));
|
auto result = shard_request_manager.Request(state, std::move(new_vertices));
|
||||||
|
|
||||||
RC_ASSERT(result.size() == 1);
|
RC_ASSERT(result.size() == 1);
|
||||||
RC_ASSERT(result[0].success);
|
RC_ASSERT(!result[0].error.has_value());
|
||||||
|
|
||||||
correctness_model.emplace(std::make_pair(create_vertex.first, create_vertex.second));
|
correctness_model.emplace(std::make_pair(create_vertex.first, create_vertex.second));
|
||||||
}
|
}
|
||||||
|
@ -343,6 +343,9 @@ target_link_libraries(${test_prefix}storage_v3_edge mg-storage-v3)
|
|||||||
add_unit_test(storage_v3_isolation_level.cpp)
|
add_unit_test(storage_v3_isolation_level.cpp)
|
||||||
target_link_libraries(${test_prefix}storage_v3_isolation_level mg-storage-v3)
|
target_link_libraries(${test_prefix}storage_v3_isolation_level mg-storage-v3)
|
||||||
|
|
||||||
|
add_unit_test(storage_v3_shard_rsm.cpp)
|
||||||
|
target_link_libraries(${test_prefix}storage_v3_shard_rsm mg-storage-v3)
|
||||||
|
|
||||||
add_unit_test(replication_persistence_helper.cpp)
|
add_unit_test(replication_persistence_helper.cpp)
|
||||||
target_link_libraries(${test_prefix}replication_persistence_helper mg-storage-v2)
|
target_link_libraries(${test_prefix}replication_persistence_helper mg-storage-v2)
|
||||||
|
|
||||||
|
@ -187,7 +187,7 @@ void ExecuteOp(msgs::ShardRequestManager<LocalTransport> &shard_request_manager,
|
|||||||
auto result = shard_request_manager.Request(state, std::move(new_vertices));
|
auto result = shard_request_manager.Request(state, std::move(new_vertices));
|
||||||
|
|
||||||
MG_ASSERT(result.size() == 1);
|
MG_ASSERT(result.size() == 1);
|
||||||
MG_ASSERT(result[0].success);
|
MG_ASSERT(!result[0].error.has_value());
|
||||||
|
|
||||||
correctness_model.emplace(std::make_pair(create_vertex.first, create_vertex.second));
|
correctness_model.emplace(std::make_pair(create_vertex.first, create_vertex.second));
|
||||||
}
|
}
|
||||||
|
@ -131,6 +131,7 @@ void TestCreateVertices(msgs::ShardRequestManagerInterface &shard_request_manage
|
|||||||
|
|
||||||
auto result = shard_request_manager.Request(state, std::move(new_vertices));
|
auto result = shard_request_manager.Request(state, std::move(new_vertices));
|
||||||
EXPECT_EQ(result.size(), 1);
|
EXPECT_EQ(result.size(), 1);
|
||||||
|
EXPECT_FALSE(result[0].error.has_value()) << result[0].error->message;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestCreateExpand(msgs::ShardRequestManagerInterface &shard_request_manager) {
|
void TestCreateExpand(msgs::ShardRequestManagerInterface &shard_request_manager) {
|
||||||
@ -151,7 +152,7 @@ void TestCreateExpand(msgs::ShardRequestManagerInterface &shard_request_manager)
|
|||||||
|
|
||||||
auto responses = shard_request_manager.Request(state, std::move(new_expands));
|
auto responses = shard_request_manager.Request(state, std::move(new_expands));
|
||||||
MG_ASSERT(responses.size() == 1);
|
MG_ASSERT(responses.size() == 1);
|
||||||
MG_ASSERT(responses[0].success);
|
MG_ASSERT(!responses[0].error.has_value());
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestExpandOne(msgs::ShardRequestManagerInterface &shard_request_manager) {
|
void TestExpandOne(msgs::ShardRequestManagerInterface &shard_request_manager) {
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include <gtest/gtest-death-test.h>
|
#include <gtest/gtest-death-test.h>
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include "common/errors.hpp"
|
||||||
#include "coordinator/hybrid_logical_clock.hpp"
|
#include "coordinator/hybrid_logical_clock.hpp"
|
||||||
#include "io/time.hpp"
|
#include "io/time.hpp"
|
||||||
#include "storage/v3/delta.hpp"
|
#include "storage/v3/delta.hpp"
|
||||||
@ -579,7 +580,7 @@ TEST_P(StorageV3, VertexDeleteSerializationError) {
|
|||||||
EXPECT_EQ(CountVertices(acc2, View::NEW), 1U);
|
EXPECT_EQ(CountVertices(acc2, View::NEW), 1U);
|
||||||
auto res = acc2.DeleteVertex(&*vertex);
|
auto res = acc2.DeleteVertex(&*vertex);
|
||||||
ASSERT_TRUE(res.HasError());
|
ASSERT_TRUE(res.HasError());
|
||||||
ASSERT_EQ(res.GetError(), Error::SERIALIZATION_ERROR);
|
ASSERT_EQ(res.GetError(), SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR));
|
||||||
EXPECT_EQ(CountVertices(acc2, View::OLD), 1U);
|
EXPECT_EQ(CountVertices(acc2, View::OLD), 1U);
|
||||||
EXPECT_EQ(CountVertices(acc2, View::NEW), 1U);
|
EXPECT_EQ(CountVertices(acc2, View::NEW), 1U);
|
||||||
acc2.AdvanceCommand();
|
acc2.AdvanceCommand();
|
||||||
@ -660,12 +661,11 @@ TEST_P(StorageV3, VertexDeleteSpecialCases) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TError, typename TResultHolder>
|
template <typename T>
|
||||||
void AssertErrorInVariant(TResultHolder &holder, TError error_type) {
|
void AssertShardErrorEqual(const ShardResult<T> &lhs, const ShardError &rhs) {
|
||||||
ASSERT_TRUE(holder.HasError());
|
ASSERT_TRUE(lhs.HasError());
|
||||||
const auto error = holder.GetError();
|
const auto error = lhs.GetError();
|
||||||
ASSERT_TRUE(std::holds_alternative<TError>(error));
|
ASSERT_EQ(error, rhs);
|
||||||
ASSERT_EQ(std::get<TError>(error), error_type);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOLINTNEXTLINE(hicpp-special-member-functions)
|
// NOLINTNEXTLINE(hicpp-special-member-functions)
|
||||||
@ -711,20 +711,20 @@ TEST_P(StorageV3, VertexDeleteLabel) {
|
|||||||
|
|
||||||
// Check whether label 5 exists
|
// Check whether label 5 exists
|
||||||
ASSERT_FALSE(vertex->HasLabel(label5, View::OLD).GetValue());
|
ASSERT_FALSE(vertex->HasLabel(label5, View::OLD).GetValue());
|
||||||
ASSERT_EQ(vertex->HasLabel(label5, View::NEW).GetError(), Error::DELETED_OBJECT);
|
ASSERT_EQ(vertex->HasLabel(label5, View::NEW).GetError(), SHARD_ERROR(ErrorCode::DELETED_OBJECT));
|
||||||
ASSERT_EQ(vertex->Labels(View::OLD)->size(), 0);
|
ASSERT_EQ(vertex->Labels(View::OLD)->size(), 0);
|
||||||
ASSERT_EQ(vertex->Labels(View::NEW).GetError(), Error::DELETED_OBJECT);
|
ASSERT_EQ(vertex->Labels(View::NEW).GetError(), SHARD_ERROR(ErrorCode::DELETED_OBJECT));
|
||||||
|
|
||||||
// Try to add the label
|
// Try to add the label
|
||||||
{
|
{
|
||||||
auto ret = vertex->AddLabelAndValidate(label5);
|
auto ret = vertex->AddLabelAndValidate(label5);
|
||||||
AssertErrorInVariant(ret, Error::DELETED_OBJECT);
|
AssertShardErrorEqual(ret, SHARD_ERROR(ErrorCode::DELETED_OBJECT));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to remove the label
|
// Try to remove the label
|
||||||
{
|
{
|
||||||
auto ret = vertex->RemoveLabelAndValidate(label5);
|
auto ret = vertex->RemoveLabelAndValidate(label5);
|
||||||
AssertErrorInVariant(ret, Error::DELETED_OBJECT);
|
AssertShardErrorEqual(ret, SHARD_ERROR(ErrorCode::DELETED_OBJECT));
|
||||||
}
|
}
|
||||||
|
|
||||||
acc.Abort();
|
acc.Abort();
|
||||||
@ -779,33 +779,33 @@ TEST_P(StorageV3, VertexDeleteLabel) {
|
|||||||
|
|
||||||
// Check whether label 5 exists
|
// Check whether label 5 exists
|
||||||
ASSERT_TRUE(vertex->HasLabel(label5, View::OLD).GetValue());
|
ASSERT_TRUE(vertex->HasLabel(label5, View::OLD).GetValue());
|
||||||
ASSERT_EQ(vertex->HasLabel(label5, View::NEW).GetError(), Error::DELETED_OBJECT);
|
ASSERT_EQ(vertex->HasLabel(label5, View::NEW).GetError(), SHARD_ERROR(ErrorCode::DELETED_OBJECT));
|
||||||
{
|
{
|
||||||
auto labels = vertex->Labels(View::OLD).GetValue();
|
auto labels = vertex->Labels(View::OLD).GetValue();
|
||||||
ASSERT_EQ(labels.size(), 1);
|
ASSERT_EQ(labels.size(), 1);
|
||||||
ASSERT_EQ(labels[0], label5);
|
ASSERT_EQ(labels[0], label5);
|
||||||
}
|
}
|
||||||
ASSERT_EQ(vertex->Labels(View::NEW).GetError(), Error::DELETED_OBJECT);
|
ASSERT_EQ(vertex->Labels(View::NEW).GetError(), SHARD_ERROR(ErrorCode::DELETED_OBJECT));
|
||||||
|
|
||||||
// Advance command
|
// Advance command
|
||||||
acc.AdvanceCommand();
|
acc.AdvanceCommand();
|
||||||
|
|
||||||
// Check whether label 5 exists
|
// Check whether label 5 exists
|
||||||
ASSERT_EQ(vertex->HasLabel(label5, View::OLD).GetError(), Error::DELETED_OBJECT);
|
ASSERT_EQ(vertex->HasLabel(label5, View::OLD).GetError(), SHARD_ERROR(ErrorCode::DELETED_OBJECT));
|
||||||
ASSERT_EQ(vertex->HasLabel(label5, View::NEW).GetError(), Error::DELETED_OBJECT);
|
ASSERT_EQ(vertex->HasLabel(label5, View::NEW).GetError(), SHARD_ERROR(ErrorCode::DELETED_OBJECT));
|
||||||
ASSERT_EQ(vertex->Labels(View::OLD).GetError(), Error::DELETED_OBJECT);
|
ASSERT_EQ(vertex->Labels(View::OLD).GetError(), SHARD_ERROR(ErrorCode::DELETED_OBJECT));
|
||||||
ASSERT_EQ(vertex->Labels(View::NEW).GetError(), Error::DELETED_OBJECT);
|
ASSERT_EQ(vertex->Labels(View::NEW).GetError(), SHARD_ERROR(ErrorCode::DELETED_OBJECT));
|
||||||
|
|
||||||
// Try to add the label
|
// Try to add the label
|
||||||
{
|
{
|
||||||
auto ret = vertex->AddLabelAndValidate(label5);
|
auto ret = vertex->AddLabelAndValidate(label5);
|
||||||
AssertErrorInVariant(ret, Error::DELETED_OBJECT);
|
AssertShardErrorEqual(ret, SHARD_ERROR(ErrorCode::DELETED_OBJECT));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to remove the label
|
// Try to remove the label
|
||||||
{
|
{
|
||||||
auto ret = vertex->RemoveLabelAndValidate(label5);
|
auto ret = vertex->RemoveLabelAndValidate(label5);
|
||||||
AssertErrorInVariant(ret, Error::DELETED_OBJECT);
|
AssertShardErrorEqual(ret, SHARD_ERROR(ErrorCode::DELETED_OBJECT));
|
||||||
}
|
}
|
||||||
|
|
||||||
acc.Abort();
|
acc.Abort();
|
||||||
@ -855,14 +855,14 @@ TEST_P(StorageV3, VertexDeleteProperty) {
|
|||||||
|
|
||||||
// Check whether label 5 exists
|
// Check whether label 5 exists
|
||||||
ASSERT_TRUE(vertex->GetProperty(property5, View::OLD)->IsNull());
|
ASSERT_TRUE(vertex->GetProperty(property5, View::OLD)->IsNull());
|
||||||
ASSERT_EQ(vertex->GetProperty(property5, View::NEW).GetError(), Error::DELETED_OBJECT);
|
ASSERT_EQ(vertex->GetProperty(property5, View::NEW).GetError(), SHARD_ERROR(ErrorCode::DELETED_OBJECT));
|
||||||
ASSERT_EQ(vertex->Properties(View::OLD)->size(), 0);
|
ASSERT_EQ(vertex->Properties(View::OLD)->size(), 0);
|
||||||
ASSERT_EQ(vertex->Properties(View::NEW).GetError(), Error::DELETED_OBJECT);
|
ASSERT_EQ(vertex->Properties(View::NEW).GetError(), SHARD_ERROR(ErrorCode::DELETED_OBJECT));
|
||||||
|
|
||||||
// Try to set the property5
|
// Try to set the property5
|
||||||
{
|
{
|
||||||
auto ret = vertex->SetPropertyAndValidate(property5, PropertyValue("haihai"));
|
auto ret = vertex->SetPropertyAndValidate(property5, PropertyValue("haihai"));
|
||||||
AssertErrorInVariant(ret, Error::DELETED_OBJECT);
|
AssertShardErrorEqual(ret, SHARD_ERROR(ErrorCode::DELETED_OBJECT));
|
||||||
}
|
}
|
||||||
|
|
||||||
acc.Abort();
|
acc.Abort();
|
||||||
@ -918,27 +918,27 @@ TEST_P(StorageV3, VertexDeleteProperty) {
|
|||||||
|
|
||||||
// Check whether property 5 exists
|
// Check whether property 5 exists
|
||||||
ASSERT_EQ(vertex->GetProperty(property5, View::OLD)->ValueString(), "nandare");
|
ASSERT_EQ(vertex->GetProperty(property5, View::OLD)->ValueString(), "nandare");
|
||||||
ASSERT_EQ(vertex->GetProperty(property5, View::NEW).GetError(), Error::DELETED_OBJECT);
|
ASSERT_EQ(vertex->GetProperty(property5, View::NEW).GetError(), SHARD_ERROR(ErrorCode::DELETED_OBJECT));
|
||||||
{
|
{
|
||||||
auto properties = vertex->Properties(View::OLD).GetValue();
|
auto properties = vertex->Properties(View::OLD).GetValue();
|
||||||
ASSERT_EQ(properties.size(), 1);
|
ASSERT_EQ(properties.size(), 1);
|
||||||
ASSERT_EQ(properties[property5].ValueString(), "nandare");
|
ASSERT_EQ(properties[property5].ValueString(), "nandare");
|
||||||
}
|
}
|
||||||
ASSERT_EQ(vertex->Properties(View::NEW).GetError(), Error::DELETED_OBJECT);
|
ASSERT_EQ(vertex->Properties(View::NEW).GetError(), SHARD_ERROR(ErrorCode::DELETED_OBJECT));
|
||||||
|
|
||||||
// Advance command
|
// Advance command
|
||||||
acc.AdvanceCommand();
|
acc.AdvanceCommand();
|
||||||
|
|
||||||
// Check whether property 5 exists
|
// Check whether property 5 exists
|
||||||
ASSERT_EQ(vertex->GetProperty(property5, View::OLD).GetError(), Error::DELETED_OBJECT);
|
ASSERT_EQ(vertex->GetProperty(property5, View::OLD).GetError(), SHARD_ERROR(ErrorCode::DELETED_OBJECT));
|
||||||
ASSERT_EQ(vertex->GetProperty(property5, View::NEW).GetError(), Error::DELETED_OBJECT);
|
ASSERT_EQ(vertex->GetProperty(property5, View::NEW).GetError(), SHARD_ERROR(ErrorCode::DELETED_OBJECT));
|
||||||
ASSERT_EQ(vertex->Properties(View::OLD).GetError(), Error::DELETED_OBJECT);
|
ASSERT_EQ(vertex->Properties(View::OLD).GetError(), SHARD_ERROR(ErrorCode::DELETED_OBJECT));
|
||||||
ASSERT_EQ(vertex->Properties(View::NEW).GetError(), Error::DELETED_OBJECT);
|
ASSERT_EQ(vertex->Properties(View::NEW).GetError(), SHARD_ERROR(ErrorCode::DELETED_OBJECT));
|
||||||
|
|
||||||
// Try to set the property
|
// Try to set the property
|
||||||
{
|
{
|
||||||
auto ret = vertex->SetPropertyAndValidate(property5, PropertyValue("haihai"));
|
auto ret = vertex->SetPropertyAndValidate(property5, PropertyValue("haihai"));
|
||||||
AssertErrorInVariant(ret, Error::DELETED_OBJECT);
|
AssertShardErrorEqual(ret, SHARD_ERROR(ErrorCode::DELETED_OBJECT));
|
||||||
}
|
}
|
||||||
|
|
||||||
acc.Abort();
|
acc.Abort();
|
||||||
@ -1371,7 +1371,7 @@ TEST_P(StorageV3, VertexLabelSerializationError) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
auto res = vertex->AddLabelAndValidate(label1);
|
auto res = vertex->AddLabelAndValidate(label1);
|
||||||
AssertErrorInVariant(res, Error::SERIALIZATION_ERROR);
|
AssertShardErrorEqual(res, SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1865,7 +1865,7 @@ TEST_P(StorageV3, VertexPropertySerializationError) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
auto res = vertex->SetPropertyAndValidate(property2, PropertyValue("nandare"));
|
auto res = vertex->SetPropertyAndValidate(property2, PropertyValue("nandare"));
|
||||||
AssertErrorInVariant(res, Error::SERIALIZATION_ERROR);
|
AssertShardErrorEqual(res, SHARD_ERROR(ErrorCode::SERIALIZATION_ERROR));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2255,14 +2255,14 @@ TEST_P(StorageV3, VertexNonexistentLabelPropertyEdgeAPI) {
|
|||||||
auto vertex = CreateVertexAndValidate(acc, {}, PropertyValue{0}, {});
|
auto vertex = CreateVertexAndValidate(acc, {}, PropertyValue{0}, {});
|
||||||
|
|
||||||
// Check state before (OLD view).
|
// Check state before (OLD view).
|
||||||
ASSERT_EQ(vertex.Labels(View::OLD).GetError(), Error::NONEXISTENT_OBJECT);
|
ASSERT_EQ(vertex.Labels(View::OLD).GetError(), SHARD_ERROR(ErrorCode::NONEXISTENT_OBJECT));
|
||||||
ASSERT_EQ(vertex.HasLabel(label1, View::OLD).GetError(), Error::NONEXISTENT_OBJECT);
|
ASSERT_EQ(vertex.HasLabel(label1, View::OLD).GetError(), SHARD_ERROR(ErrorCode::NONEXISTENT_OBJECT));
|
||||||
ASSERT_EQ(vertex.Properties(View::OLD).GetError(), Error::NONEXISTENT_OBJECT);
|
ASSERT_EQ(vertex.Properties(View::OLD).GetError(), SHARD_ERROR(ErrorCode::NONEXISTENT_OBJECT));
|
||||||
ASSERT_EQ(vertex.GetProperty(property1, View::OLD).GetError(), Error::NONEXISTENT_OBJECT);
|
ASSERT_EQ(vertex.GetProperty(property1, View::OLD).GetError(), SHARD_ERROR(ErrorCode::NONEXISTENT_OBJECT));
|
||||||
ASSERT_EQ(vertex.InEdges(View::OLD).GetError(), Error::NONEXISTENT_OBJECT);
|
ASSERT_EQ(vertex.InEdges(View::OLD).GetError(), SHARD_ERROR(ErrorCode::NONEXISTENT_OBJECT));
|
||||||
ASSERT_EQ(vertex.OutEdges(View::OLD).GetError(), Error::NONEXISTENT_OBJECT);
|
ASSERT_EQ(vertex.OutEdges(View::OLD).GetError(), SHARD_ERROR(ErrorCode::NONEXISTENT_OBJECT));
|
||||||
ASSERT_EQ(vertex.InDegree(View::OLD).GetError(), Error::NONEXISTENT_OBJECT);
|
ASSERT_EQ(vertex.InDegree(View::OLD).GetError(), SHARD_ERROR(ErrorCode::NONEXISTENT_OBJECT));
|
||||||
ASSERT_EQ(vertex.OutDegree(View::OLD).GetError(), Error::NONEXISTENT_OBJECT);
|
ASSERT_EQ(vertex.OutDegree(View::OLD).GetError(), SHARD_ERROR(ErrorCode::NONEXISTENT_OBJECT));
|
||||||
|
|
||||||
// Check state before (NEW view).
|
// Check state before (NEW view).
|
||||||
ASSERT_EQ(vertex.Labels(View::NEW)->size(), 0);
|
ASSERT_EQ(vertex.Labels(View::NEW)->size(), 0);
|
||||||
@ -2282,14 +2282,14 @@ TEST_P(StorageV3, VertexNonexistentLabelPropertyEdgeAPI) {
|
|||||||
.HasValue());
|
.HasValue());
|
||||||
|
|
||||||
// Check state after (OLD view).
|
// Check state after (OLD view).
|
||||||
ASSERT_EQ(vertex.Labels(View::OLD).GetError(), Error::NONEXISTENT_OBJECT);
|
ASSERT_EQ(vertex.Labels(View::OLD).GetError(), SHARD_ERROR(ErrorCode::NONEXISTENT_OBJECT));
|
||||||
ASSERT_EQ(vertex.HasLabel(label1, View::OLD).GetError(), Error::NONEXISTENT_OBJECT);
|
ASSERT_EQ(vertex.HasLabel(label1, View::OLD).GetError(), SHARD_ERROR(ErrorCode::NONEXISTENT_OBJECT));
|
||||||
ASSERT_EQ(vertex.Properties(View::OLD).GetError(), Error::NONEXISTENT_OBJECT);
|
ASSERT_EQ(vertex.Properties(View::OLD).GetError(), SHARD_ERROR(ErrorCode::NONEXISTENT_OBJECT));
|
||||||
ASSERT_EQ(vertex.GetProperty(property1, View::OLD).GetError(), Error::NONEXISTENT_OBJECT);
|
ASSERT_EQ(vertex.GetProperty(property1, View::OLD).GetError(), SHARD_ERROR(ErrorCode::NONEXISTENT_OBJECT));
|
||||||
ASSERT_EQ(vertex.InEdges(View::OLD).GetError(), Error::NONEXISTENT_OBJECT);
|
ASSERT_EQ(vertex.InEdges(View::OLD).GetError(), SHARD_ERROR(ErrorCode::NONEXISTENT_OBJECT));
|
||||||
ASSERT_EQ(vertex.OutEdges(View::OLD).GetError(), Error::NONEXISTENT_OBJECT);
|
ASSERT_EQ(vertex.OutEdges(View::OLD).GetError(), SHARD_ERROR(ErrorCode::NONEXISTENT_OBJECT));
|
||||||
ASSERT_EQ(vertex.InDegree(View::OLD).GetError(), Error::NONEXISTENT_OBJECT);
|
ASSERT_EQ(vertex.InDegree(View::OLD).GetError(), SHARD_ERROR(ErrorCode::NONEXISTENT_OBJECT));
|
||||||
ASSERT_EQ(vertex.OutDegree(View::OLD).GetError(), Error::NONEXISTENT_OBJECT);
|
ASSERT_EQ(vertex.OutDegree(View::OLD).GetError(), SHARD_ERROR(ErrorCode::NONEXISTENT_OBJECT));
|
||||||
|
|
||||||
// Check state after (NEW view).
|
// Check state after (NEW view).
|
||||||
ASSERT_EQ(vertex.Labels(View::NEW)->size(), 1);
|
ASSERT_EQ(vertex.Labels(View::NEW)->size(), 1);
|
||||||
@ -2657,42 +2657,31 @@ TEST_P(StorageV3, TestCreateVertexAndValidate) {
|
|||||||
|
|
||||||
ASSERT_TRUE(vertex2.HasError());
|
ASSERT_TRUE(vertex2.HasError());
|
||||||
auto error = vertex2.GetError();
|
auto error = vertex2.GetError();
|
||||||
auto error_ptr = std::get_if<memgraph::storage::v3::Error>(&error);
|
ASSERT_TRUE(error == common::ErrorCode::VERTEX_ALREADY_INSERTED);
|
||||||
ASSERT_TRUE(error_ptr);
|
|
||||||
ASSERT_TRUE(*error_ptr == storage::v3::Error::VERTEX_ALREADY_INSERTED);
|
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto acc = store.Access(GetNextHlc());
|
auto acc = store.Access(GetNextHlc());
|
||||||
auto vertex = acc.CreateVertexAndValidate({primary_label}, {PropertyValue{0}}, {});
|
auto vertex = acc.CreateVertexAndValidate({primary_label}, {PropertyValue{0}}, {});
|
||||||
ASSERT_TRUE(vertex.HasError());
|
ASSERT_TRUE(vertex.HasError());
|
||||||
ASSERT_TRUE(std::holds_alternative<SchemaViolation>(vertex.GetError()));
|
EXPECT_EQ(vertex.GetError(), SHARD_ERROR(ErrorCode::SCHEMA_VERTEX_SECONDARY_LABEL_IS_PRIMARY));
|
||||||
EXPECT_EQ(std::get<SchemaViolation>(vertex.GetError()),
|
|
||||||
SchemaViolation(SchemaViolation::ValidationStatus::VERTEX_SECONDARY_LABEL_IS_PRIMARY, primary_label));
|
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto acc = store.Access(GetNextHlc());
|
auto acc = store.Access(GetNextHlc());
|
||||||
auto vertex = acc.CreateVertexAndValidate({primary_label}, {PropertyValue{0}}, {});
|
auto vertex = acc.CreateVertexAndValidate({primary_label}, {PropertyValue{0}}, {});
|
||||||
ASSERT_TRUE(vertex.HasError());
|
ASSERT_TRUE(vertex.HasError());
|
||||||
ASSERT_TRUE(std::holds_alternative<SchemaViolation>(vertex.GetError()));
|
EXPECT_EQ(vertex.GetError(), SHARD_ERROR(ErrorCode::SCHEMA_VERTEX_SECONDARY_LABEL_IS_PRIMARY));
|
||||||
EXPECT_EQ(std::get<SchemaViolation>(vertex.GetError()),
|
|
||||||
SchemaViolation(SchemaViolation::ValidationStatus::VERTEX_SECONDARY_LABEL_IS_PRIMARY, primary_label));
|
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto acc = store.Access(GetNextHlc());
|
auto acc = store.Access(GetNextHlc());
|
||||||
auto vertex = acc.CreateVertexAndValidate({}, {}, {});
|
auto vertex = acc.CreateVertexAndValidate({}, {}, {});
|
||||||
ASSERT_TRUE(vertex.HasError());
|
ASSERT_TRUE(vertex.HasError());
|
||||||
ASSERT_TRUE(std::holds_alternative<SchemaViolation>(vertex.GetError()));
|
EXPECT_EQ(vertex.GetError(), SHARD_ERROR(ErrorCode::SCHEMA_VERTEX_PRIMARY_PROPERTIES_UNDEFINED));
|
||||||
EXPECT_EQ(std::get<SchemaViolation>(vertex.GetError()),
|
|
||||||
SchemaViolation(SchemaViolation::ValidationStatus::VERTEX_PRIMARY_PROPERTIES_UNDEFINED, primary_label));
|
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto acc = store.Access(GetNextHlc());
|
auto acc = store.Access(GetNextHlc());
|
||||||
auto vertex = acc.CreateVertexAndValidate({}, {PropertyValue{"test"}}, {});
|
auto vertex = acc.CreateVertexAndValidate({}, {PropertyValue{"test"}}, {});
|
||||||
ASSERT_TRUE(vertex.HasError());
|
ASSERT_TRUE(vertex.HasError());
|
||||||
ASSERT_TRUE(std::holds_alternative<SchemaViolation>(vertex.GetError()));
|
EXPECT_EQ(vertex.GetError(), SHARD_ERROR(ErrorCode::SCHEMA_VERTEX_PROPERTY_WRONG_TYPE));
|
||||||
EXPECT_EQ(std::get<SchemaViolation>(vertex.GetError()),
|
|
||||||
SchemaViolation(SchemaViolation::ValidationStatus::VERTEX_PROPERTY_WRONG_TYPE, primary_label,
|
|
||||||
{primary_property, common::SchemaType::INT}, PropertyValue("test")));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // namespace memgraph::storage::v3::tests
|
} // namespace memgraph::storage::v3::tests
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
#include "storage/v3/name_id_mapper.hpp"
|
#include "storage/v3/name_id_mapper.hpp"
|
||||||
#include "storage/v3/property_value.hpp"
|
#include "storage/v3/property_value.hpp"
|
||||||
#include "storage/v3/shard.hpp"
|
#include "storage/v3/shard.hpp"
|
||||||
#include "storage/v3/shard_operation_result.hpp"
|
|
||||||
|
|
||||||
namespace memgraph::storage::v3::tests {
|
namespace memgraph::storage::v3::tests {
|
||||||
using testing::UnorderedElementsAre;
|
using testing::UnorderedElementsAre;
|
||||||
@ -39,7 +38,7 @@ class StorageEdgeTest : public ::testing::TestWithParam<bool> {
|
|||||||
return store.NameToEdgeType(edge_type_name);
|
return store.NameToEdgeType(edge_type_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ShardOperationResult<VertexAccessor> CreateVertex(Shard::Accessor &acc, const PropertyValue &key) {
|
static ShardResult<VertexAccessor> CreateVertex(Shard::Accessor &acc, const PropertyValue &key) {
|
||||||
return acc.CreateVertexAndValidate({}, {key}, {});
|
return acc.CreateVertexAndValidate({}, {key}, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1157,7 +1156,7 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) {
|
|||||||
{
|
{
|
||||||
auto ret = acc.DeleteVertex(&vertex_from.value());
|
auto ret = acc.DeleteVertex(&vertex_from.value());
|
||||||
ASSERT_TRUE(ret.HasError());
|
ASSERT_TRUE(ret.HasError());
|
||||||
ASSERT_EQ(ret.GetError(), Error::VERTEX_HAS_EDGES);
|
ASSERT_EQ(ret.GetError(), SHARD_ERROR(ErrorCode::VERTEX_HAS_EDGES));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detach delete vertex
|
// Detach delete vertex
|
||||||
@ -1170,8 +1169,8 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) {
|
|||||||
// Check edges
|
// Check edges
|
||||||
ASSERT_EQ(vertex_from->InEdges(View::OLD)->size(), 0);
|
ASSERT_EQ(vertex_from->InEdges(View::OLD)->size(), 0);
|
||||||
ASSERT_EQ(*vertex_from->InDegree(View::OLD), 0);
|
ASSERT_EQ(*vertex_from->InDegree(View::OLD), 0);
|
||||||
ASSERT_EQ(vertex_from->InEdges(View::NEW).GetError(), Error::DELETED_OBJECT);
|
ASSERT_EQ(vertex_from->InEdges(View::NEW).GetError(), SHARD_ERROR(ErrorCode::DELETED_OBJECT));
|
||||||
ASSERT_EQ(vertex_from->InDegree(View::NEW).GetError(), Error::DELETED_OBJECT);
|
ASSERT_EQ(vertex_from->InDegree(View::NEW).GetError(), SHARD_ERROR(ErrorCode::DELETED_OBJECT));
|
||||||
{
|
{
|
||||||
auto ret = vertex_from->OutEdges(View::OLD);
|
auto ret = vertex_from->OutEdges(View::OLD);
|
||||||
ASSERT_TRUE(ret.HasValue());
|
ASSERT_TRUE(ret.HasValue());
|
||||||
@ -1184,8 +1183,8 @@ TEST_P(StorageEdgeTest, VertexDetachDeleteSingleCommit) {
|
|||||||
ASSERT_EQ(e.From(), from_id);
|
ASSERT_EQ(e.From(), from_id);
|
||||||
ASSERT_EQ(e.To(), to_id);
|
ASSERT_EQ(e.To(), to_id);
|
||||||
}
|
}
|
||||||
ASSERT_EQ(vertex_from->OutEdges(View::NEW).GetError(), Error::DELETED_OBJECT);
|
ASSERT_EQ(vertex_from->OutEdges(View::NEW).GetError(), SHARD_ERROR(ErrorCode::DELETED_OBJECT));
|
||||||
ASSERT_EQ(vertex_from->OutDegree(View::NEW).GetError(), Error::DELETED_OBJECT);
|
ASSERT_EQ(vertex_from->OutDegree(View::NEW).GetError(), SHARD_ERROR(ErrorCode::DELETED_OBJECT));
|
||||||
{
|
{
|
||||||
auto ret = vertex_to->InEdges(View::OLD);
|
auto ret = vertex_to->InEdges(View::OLD);
|
||||||
ASSERT_TRUE(ret.HasValue());
|
ASSERT_TRUE(ret.HasValue());
|
||||||
|
@ -14,10 +14,10 @@
|
|||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
#include <optional>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "common/errors.hpp"
|
||||||
#include "common/types.hpp"
|
#include "common/types.hpp"
|
||||||
#include "storage/v3/id_types.hpp"
|
#include "storage/v3/id_types.hpp"
|
||||||
#include "storage/v3/property_value.hpp"
|
#include "storage/v3/property_value.hpp"
|
||||||
@ -150,7 +150,15 @@ TEST_F(SchemaTest, TestSchemaDrop) {
|
|||||||
|
|
||||||
class SchemaValidatorTest : public testing::Test {
|
class SchemaValidatorTest : public testing::Test {
|
||||||
private:
|
private:
|
||||||
NameIdMapper id_mapper_{{{1, "label1"}, {2, "label2"}, {3, "prop1"}, {4, "prop2"}, {5, "prop3"}}};
|
NameIdMapper id_mapper_{{{1, "label1"},
|
||||||
|
{2, "label2"},
|
||||||
|
{3, "prop1"},
|
||||||
|
{4, "prop2"},
|
||||||
|
{5, "prop3"},
|
||||||
|
{6, "label4"},
|
||||||
|
{7, "label5"},
|
||||||
|
{8, "label6"},
|
||||||
|
{9, "test"}}};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void SetUp() override {
|
void SetUp() override {
|
||||||
@ -162,9 +170,8 @@ class SchemaValidatorTest : public testing::Test {
|
|||||||
|
|
||||||
PropertyId NameToProperty(const std::string &name) { return PropertyId::FromUint(id_mapper_.NameToId(name)); }
|
PropertyId NameToProperty(const std::string &name) { return PropertyId::FromUint(id_mapper_.NameToId(name)); }
|
||||||
|
|
||||||
protected:
|
|
||||||
Schemas schemas;
|
Schemas schemas;
|
||||||
SchemaValidator schema_validator{schemas};
|
SchemaValidator schema_validator{schemas, id_mapper_};
|
||||||
PropertyId prop_string{NameToProperty("prop1")};
|
PropertyId prop_string{NameToProperty("prop1")};
|
||||||
PropertyId prop_int{NameToProperty("prop2")};
|
PropertyId prop_int{NameToProperty("prop2")};
|
||||||
PropertyId prop_duration{NameToProperty("prop3")};
|
PropertyId prop_duration{NameToProperty("prop3")};
|
||||||
@ -179,100 +186,92 @@ TEST_F(SchemaValidatorTest, TestSchemaValidateVertexCreate) {
|
|||||||
// Validate against secondary label
|
// Validate against secondary label
|
||||||
{
|
{
|
||||||
const auto schema_violation = schema_validator.ValidateVertexCreate(NameToLabel("test"), {}, {PropertyValue(1)});
|
const auto schema_violation = schema_validator.ValidateVertexCreate(NameToLabel("test"), {}, {PropertyValue(1)});
|
||||||
ASSERT_NE(schema_violation, std::nullopt);
|
ASSERT_TRUE(schema_violation.HasError());
|
||||||
EXPECT_EQ(*schema_violation,
|
EXPECT_EQ(schema_violation.GetError(), SHARD_ERROR(ErrorCode::SCHEMA_NO_SCHEMA_DEFINED_FOR_LABEL));
|
||||||
SchemaViolation(SchemaViolation::ValidationStatus::NO_SCHEMA_DEFINED_FOR_LABEL, NameToLabel("test")));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const auto schema_violation = schema_validator.ValidateVertexCreate(label2, {}, {});
|
const auto schema_violation = schema_validator.ValidateVertexCreate(label2, {}, {});
|
||||||
ASSERT_NE(schema_violation, std::nullopt);
|
ASSERT_TRUE(schema_violation.HasError());
|
||||||
EXPECT_EQ(*schema_violation,
|
EXPECT_EQ(schema_violation.GetError(), SHARD_ERROR(ErrorCode::SCHEMA_VERTEX_PRIMARY_PROPERTIES_UNDEFINED));
|
||||||
SchemaViolation(SchemaViolation::ValidationStatus::VERTEX_PRIMARY_PROPERTIES_UNDEFINED, label2));
|
|
||||||
}
|
}
|
||||||
// Validate wrong secondary label
|
// Validate wrong secondary label
|
||||||
{
|
{
|
||||||
const auto schema_violation = schema_validator.ValidateVertexCreate(label1, {label1}, {PropertyValue("test")});
|
const auto schema_violation = schema_validator.ValidateVertexCreate(label1, {label1}, {PropertyValue("test")});
|
||||||
ASSERT_NE(schema_violation, std::nullopt);
|
ASSERT_TRUE(schema_violation.HasError());
|
||||||
EXPECT_EQ(*schema_violation,
|
EXPECT_EQ(schema_violation.GetError(), SHARD_ERROR(ErrorCode::SCHEMA_VERTEX_SECONDARY_LABEL_IS_PRIMARY));
|
||||||
SchemaViolation(SchemaViolation::ValidationStatus::VERTEX_SECONDARY_LABEL_IS_PRIMARY, label1));
|
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const auto schema_violation = schema_validator.ValidateVertexCreate(label1, {label2}, {PropertyValue("test")});
|
const auto schema_violation = schema_validator.ValidateVertexCreate(label1, {label2}, {PropertyValue("test")});
|
||||||
ASSERT_NE(schema_violation, std::nullopt);
|
ASSERT_TRUE(schema_violation.HasError());
|
||||||
EXPECT_EQ(*schema_violation,
|
EXPECT_EQ(schema_violation.GetError(), SHARD_ERROR(ErrorCode::SCHEMA_VERTEX_SECONDARY_LABEL_IS_PRIMARY));
|
||||||
SchemaViolation(SchemaViolation::ValidationStatus::VERTEX_SECONDARY_LABEL_IS_PRIMARY, label2));
|
|
||||||
}
|
}
|
||||||
// Validate wrong property type
|
// Validate wrong property type
|
||||||
{
|
{
|
||||||
const auto schema_violation = schema_validator.ValidateVertexCreate(label1, {}, {PropertyValue(1)});
|
const auto schema_violation = schema_validator.ValidateVertexCreate(label1, {}, {PropertyValue(1)});
|
||||||
ASSERT_NE(schema_violation, std::nullopt);
|
ASSERT_TRUE(schema_violation.HasError());
|
||||||
EXPECT_EQ(*schema_violation, SchemaViolation(SchemaViolation::ValidationStatus::VERTEX_PROPERTY_WRONG_TYPE, label1,
|
EXPECT_EQ(schema_violation.GetError(), SHARD_ERROR(ErrorCode::SCHEMA_VERTEX_PROPERTY_WRONG_TYPE));
|
||||||
schema_prop_string, PropertyValue(1)));
|
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const auto schema_violation =
|
const auto schema_violation =
|
||||||
schema_validator.ValidateVertexCreate(label2, {}, {PropertyValue("test"), PropertyValue(12), PropertyValue(1)});
|
schema_validator.ValidateVertexCreate(label2, {}, {PropertyValue("test"), PropertyValue(12), PropertyValue(1)});
|
||||||
ASSERT_NE(schema_violation, std::nullopt);
|
ASSERT_TRUE(schema_violation.HasError());
|
||||||
EXPECT_EQ(*schema_violation, SchemaViolation(SchemaViolation::ValidationStatus::VERTEX_PROPERTY_WRONG_TYPE, label2,
|
EXPECT_EQ(schema_violation.GetError(), SHARD_ERROR(ErrorCode::SCHEMA_VERTEX_PROPERTY_WRONG_TYPE));
|
||||||
schema_prop_duration, PropertyValue(1)));
|
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const auto wrong_prop = PropertyValue(TemporalData(TemporalType::Date, 1234));
|
const auto wrong_prop = PropertyValue(TemporalData(TemporalType::Date, 1234));
|
||||||
const auto schema_violation =
|
const auto schema_violation =
|
||||||
schema_validator.ValidateVertexCreate(label2, {}, {PropertyValue("test"), PropertyValue(12), wrong_prop});
|
schema_validator.ValidateVertexCreate(label2, {}, {PropertyValue("test"), PropertyValue(12), wrong_prop});
|
||||||
ASSERT_NE(schema_violation, std::nullopt);
|
ASSERT_TRUE(schema_violation.HasError());
|
||||||
EXPECT_EQ(*schema_violation, SchemaViolation(SchemaViolation::ValidationStatus::VERTEX_PROPERTY_WRONG_TYPE, label2,
|
EXPECT_EQ(schema_violation.GetError(), SHARD_ERROR(ErrorCode::SCHEMA_VERTEX_PROPERTY_WRONG_TYPE));
|
||||||
schema_prop_duration, wrong_prop));
|
|
||||||
}
|
}
|
||||||
// Passing validations
|
// Passing validations
|
||||||
EXPECT_EQ(schema_validator.ValidateVertexCreate(label1, {}, {PropertyValue("test")}), std::nullopt);
|
EXPECT_FALSE(schema_validator.ValidateVertexCreate(label1, {}, {PropertyValue("test")}).HasError());
|
||||||
EXPECT_EQ(schema_validator.ValidateVertexCreate(label1, {NameToLabel("label3"), NameToLabel("label4")},
|
EXPECT_FALSE(
|
||||||
{PropertyValue("test")}),
|
schema_validator
|
||||||
std::nullopt);
|
.ValidateVertexCreate(label1, {NameToLabel("label3"), NameToLabel("label4")}, {PropertyValue("test")})
|
||||||
EXPECT_EQ(schema_validator.ValidateVertexCreate(
|
.HasError());
|
||||||
label2, {},
|
EXPECT_FALSE(schema_validator
|
||||||
{PropertyValue("test"), PropertyValue(122), PropertyValue(TemporalData(TemporalType::Duration, 1234))}),
|
.ValidateVertexCreate(label2, {},
|
||||||
std::nullopt);
|
{PropertyValue("test"), PropertyValue(122),
|
||||||
EXPECT_EQ(schema_validator.ValidateVertexCreate(label2, {NameToLabel("label5"), NameToLabel("label6")},
|
PropertyValue(TemporalData(TemporalType::Duration, 1234))})
|
||||||
|
.HasError());
|
||||||
|
EXPECT_FALSE(schema_validator
|
||||||
|
.ValidateVertexCreate(label2, {NameToLabel("label5"), NameToLabel("label6")},
|
||||||
{PropertyValue("test123"), PropertyValue(122221),
|
{PropertyValue("test123"), PropertyValue(122221),
|
||||||
PropertyValue(TemporalData(TemporalType::Duration, 12344321))}),
|
PropertyValue(TemporalData(TemporalType::Duration, 12344321))})
|
||||||
std::nullopt);
|
.HasError());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(SchemaValidatorTest, TestSchemaValidatePropertyUpdate) {
|
TEST_F(SchemaValidatorTest, TestSchemaValidatePropertyUpdate) {
|
||||||
// Validate updating of primary key
|
// Validate updating of primary key
|
||||||
{
|
{
|
||||||
const auto schema_violation = schema_validator.ValidatePropertyUpdate(label1, prop_string);
|
const auto schema_violation = schema_validator.ValidatePropertyUpdate(label1, prop_string);
|
||||||
ASSERT_NE(schema_violation, std::nullopt);
|
ASSERT_TRUE(schema_violation.HasError());
|
||||||
EXPECT_EQ(*schema_violation, SchemaViolation(SchemaViolation::ValidationStatus::VERTEX_UPDATE_PRIMARY_KEY, label1,
|
EXPECT_EQ(schema_violation.GetError(), SHARD_ERROR(ErrorCode::SCHEMA_VERTEX_UPDATE_PRIMARY_KEY));
|
||||||
schema_prop_string));
|
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const auto schema_violation = schema_validator.ValidatePropertyUpdate(label2, prop_duration);
|
const auto schema_violation = schema_validator.ValidatePropertyUpdate(label2, prop_duration);
|
||||||
ASSERT_NE(schema_violation, std::nullopt);
|
ASSERT_TRUE(schema_violation.HasError());
|
||||||
EXPECT_EQ(*schema_violation, SchemaViolation(SchemaViolation::ValidationStatus::VERTEX_UPDATE_PRIMARY_KEY, label2,
|
EXPECT_EQ(schema_violation.GetError(), SHARD_ERROR(ErrorCode::SCHEMA_VERTEX_UPDATE_PRIMARY_KEY));
|
||||||
schema_prop_duration));
|
|
||||||
}
|
}
|
||||||
EXPECT_EQ(schema_validator.ValidatePropertyUpdate(label1, prop_int), std::nullopt);
|
EXPECT_FALSE(schema_validator.ValidatePropertyUpdate(label1, prop_int).HasError());
|
||||||
EXPECT_EQ(schema_validator.ValidatePropertyUpdate(label1, prop_duration), std::nullopt);
|
EXPECT_FALSE(schema_validator.ValidatePropertyUpdate(label1, prop_duration).HasError());
|
||||||
EXPECT_EQ(schema_validator.ValidatePropertyUpdate(label2, NameToProperty("test")), std::nullopt);
|
EXPECT_FALSE(schema_validator.ValidatePropertyUpdate(label2, NameToProperty("test")).HasError());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(SchemaValidatorTest, TestSchemaValidatePropertyUpdateLabel) {
|
TEST_F(SchemaValidatorTest, TestSchemaValidatePropertyUpdateLabel) {
|
||||||
// Validate adding primary label
|
// Validate adding primary label
|
||||||
{
|
{
|
||||||
const auto schema_violation = schema_validator.ValidateLabelUpdate(label1);
|
const auto schema_violation = schema_validator.ValidateLabelUpdate(label1);
|
||||||
ASSERT_NE(schema_violation, std::nullopt);
|
ASSERT_TRUE(schema_violation.HasError());
|
||||||
EXPECT_EQ(*schema_violation,
|
EXPECT_EQ(schema_violation.GetError(), SHARD_ERROR(ErrorCode::SCHEMA_VERTEX_UPDATE_PRIMARY_LABEL));
|
||||||
SchemaViolation(SchemaViolation::ValidationStatus::VERTEX_UPDATE_PRIMARY_LABEL, label1));
|
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const auto schema_violation = schema_validator.ValidateLabelUpdate(label2);
|
const auto schema_violation = schema_validator.ValidateLabelUpdate(label2);
|
||||||
ASSERT_NE(schema_violation, std::nullopt);
|
ASSERT_TRUE(schema_violation.HasError());
|
||||||
EXPECT_EQ(*schema_violation,
|
EXPECT_EQ(schema_violation.GetError(), SHARD_ERROR(ErrorCode::SCHEMA_VERTEX_UPDATE_PRIMARY_LABEL));
|
||||||
SchemaViolation(SchemaViolation::ValidationStatus::VERTEX_UPDATE_PRIMARY_LABEL, label2));
|
|
||||||
}
|
}
|
||||||
EXPECT_EQ(schema_validator.ValidateLabelUpdate(NameToLabel("test")), std::nullopt);
|
EXPECT_FALSE(schema_validator.ValidateLabelUpdate(NameToLabel("test")).HasError());
|
||||||
}
|
}
|
||||||
} // namespace memgraph::storage::v3::tests
|
} // namespace memgraph::storage::v3::tests
|
||||||
|
316
tests/unit/storage_v3_shard_rsm.cpp
Normal file
316
tests/unit/storage_v3_shard_rsm.cpp
Normal file
@ -0,0 +1,316 @@
|
|||||||
|
// 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 <gmock/gmock-matchers.h>
|
||||||
|
#include <gmock/gmock.h>
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include <fmt/format.h>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
#include <variant>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "common/types.hpp"
|
||||||
|
#include "query/v2/requests.hpp"
|
||||||
|
#include "storage/v3/id_types.hpp"
|
||||||
|
#include "storage/v3/property_value.hpp"
|
||||||
|
#include "storage/v3/schema_validator.hpp"
|
||||||
|
#include "storage/v3/schemas.hpp"
|
||||||
|
#include "storage/v3/shard_rsm.hpp"
|
||||||
|
#include "storage/v3/temporal.hpp"
|
||||||
|
#include "storage/v3/vertex_id.hpp"
|
||||||
|
|
||||||
|
using testing::Pair;
|
||||||
|
using testing::UnorderedElementsAre;
|
||||||
|
using SchemaType = memgraph::common::SchemaType;
|
||||||
|
|
||||||
|
namespace memgraph::storage::v3::tests {
|
||||||
|
|
||||||
|
uint64_t GetTransactionId() {
|
||||||
|
static uint64_t transaction_id = 0;
|
||||||
|
return transaction_id++;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ShardRSMTest : public testing::Test {
|
||||||
|
private:
|
||||||
|
NameIdMapper id_mapper_{{{1, "primary_label"},
|
||||||
|
{2, "primary_label2"},
|
||||||
|
{3, "label"},
|
||||||
|
{4, "primary_prop1"},
|
||||||
|
{5, "primary_prop2"},
|
||||||
|
{6, "prop"}}};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
ShardRSMTest() {
|
||||||
|
PropertyValue min_pk(static_cast<int64_t>(0));
|
||||||
|
std::vector<PropertyValue> min_prim_key = {min_pk};
|
||||||
|
PropertyValue max_pk(static_cast<int64_t>(10000000));
|
||||||
|
std::vector<PropertyValue> max_prim_key = {max_pk};
|
||||||
|
|
||||||
|
auto shard_ptr1 = std::make_unique<Shard>(primary_label, min_prim_key, max_prim_key, std::vector{schema_prop});
|
||||||
|
shard_ptr1->StoreMapping({{1, "primary_label"},
|
||||||
|
{2, "primary_label2"},
|
||||||
|
{3, "label"},
|
||||||
|
{4, "primary_prop1"},
|
||||||
|
{5, "primary_prop2"},
|
||||||
|
{6, "prop"}});
|
||||||
|
shard_ptr1->CreateSchema(primary_label2, {{primary_property2, SchemaType::INT}});
|
||||||
|
shard_rsm = std::make_unique<ShardRsm>(std::move(shard_ptr1));
|
||||||
|
}
|
||||||
|
|
||||||
|
LabelId NameToLabel(const std::string &name) { return LabelId::FromUint(id_mapper_.NameToId(name)); }
|
||||||
|
|
||||||
|
PropertyId NameToProperty(const std::string &name) { return PropertyId::FromUint(id_mapper_.NameToId(name)); }
|
||||||
|
|
||||||
|
auto Commit(const auto &req) {
|
||||||
|
const coordinator::Hlc commit_timestamp{GetTransactionId()};
|
||||||
|
msgs::CommitRequest commit_req;
|
||||||
|
commit_req.transaction_id = req.transaction_id;
|
||||||
|
commit_req.commit_timestamp = commit_timestamp;
|
||||||
|
return shard_rsm->Apply(commit_req);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CreateVertex(const msgs::PrimaryKey &primary_key, const std::vector<msgs::Label> labels,
|
||||||
|
const std::vector<std::pair<msgs::PropertyId, msgs::Value>> &properties) {
|
||||||
|
msgs::NewVertex vertex = {labels, primary_key, properties};
|
||||||
|
msgs::CreateVerticesRequest create_req;
|
||||||
|
create_req.new_vertices = {vertex};
|
||||||
|
create_req.new_vertices = {vertex};
|
||||||
|
create_req.transaction_id.logical_id = GetTransactionId();
|
||||||
|
|
||||||
|
auto write_res = shard_rsm->Apply(create_req);
|
||||||
|
ASSERT_TRUE(std::holds_alternative<msgs::CreateVerticesResponse>(write_res));
|
||||||
|
|
||||||
|
auto commit_res = Commit(create_req);
|
||||||
|
ASSERT_TRUE(std::holds_alternative<msgs::CommitResponse>(commit_res));
|
||||||
|
ASSERT_FALSE(std::get<msgs::CommitResponse>(commit_res).error.has_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssertVertexExists(const msgs::PrimaryKey &primary_key, const std::vector<msgs::Label> &labels,
|
||||||
|
const std::vector<std::pair<msgs::PropertyId, msgs::Value>> &properties) {
|
||||||
|
msgs::ScanVerticesRequest scan_req;
|
||||||
|
scan_req.props_to_return = std::nullopt;
|
||||||
|
scan_req.start_id = msgs::VertexId{msgs::Label{.id = primary_label}, primary_key};
|
||||||
|
scan_req.storage_view = msgs::StorageView::OLD;
|
||||||
|
scan_req.transaction_id.logical_id = GetTransactionId();
|
||||||
|
|
||||||
|
// Make request
|
||||||
|
auto maybe_read_res = shard_rsm->Read(scan_req);
|
||||||
|
ASSERT_TRUE(std::holds_alternative<msgs::ScanVerticesResponse>(maybe_read_res));
|
||||||
|
const auto read_res = std::get<msgs::ScanVerticesResponse>(maybe_read_res);
|
||||||
|
EXPECT_FALSE(read_res.error.has_value());
|
||||||
|
EXPECT_EQ(read_res.results.size(), 1);
|
||||||
|
|
||||||
|
// Read results
|
||||||
|
const auto res = read_res.results[0];
|
||||||
|
const auto vtx_id = msgs::VertexId{msgs::Label{.id = primary_label}, primary_key};
|
||||||
|
EXPECT_EQ(res.vertex.id, vtx_id);
|
||||||
|
EXPECT_EQ(res.vertex.labels, labels);
|
||||||
|
EXPECT_EQ(res.props, properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
LabelId primary_label{NameToLabel("primary_label")};
|
||||||
|
LabelId primary_label2{NameToLabel("primary_label2")};
|
||||||
|
LabelId label{NameToLabel("label")};
|
||||||
|
PropertyId primary_property1{NameToProperty("primary_prop1")};
|
||||||
|
PropertyId primary_property2{NameToProperty("primary_prop2")};
|
||||||
|
PropertyId prop{NameToProperty("prop")};
|
||||||
|
SchemaProperty schema_prop{primary_property1, SchemaType::INT};
|
||||||
|
std::unique_ptr<ShardRsm> shard_rsm;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(ShardRSMTest, TestUpdateVertexSecondaryProperty) {
|
||||||
|
const msgs::Value primary_key_val{static_cast<int64_t>(1)};
|
||||||
|
const msgs::PrimaryKey pk{primary_key_val};
|
||||||
|
|
||||||
|
// Create Vertex
|
||||||
|
CreateVertex(pk, {}, {});
|
||||||
|
|
||||||
|
// Add property prop
|
||||||
|
static constexpr int64_t updated_vertex_id{10};
|
||||||
|
{
|
||||||
|
msgs::UpdateVerticesRequest update_req;
|
||||||
|
update_req.transaction_id.logical_id = GetTransactionId();
|
||||||
|
|
||||||
|
update_req.update_vertices =
|
||||||
|
std::vector<msgs::UpdateVertex>{{pk, {}, {}, {{msgs::PropertyId(prop), msgs::Value(updated_vertex_id)}}}};
|
||||||
|
|
||||||
|
const auto write_res = shard_rsm->Apply(update_req);
|
||||||
|
ASSERT_TRUE(std::holds_alternative<msgs::UpdateVerticesResponse>(write_res));
|
||||||
|
EXPECT_FALSE(std::get<msgs::UpdateVerticesResponse>(write_res).error.has_value());
|
||||||
|
|
||||||
|
const auto commit_res = Commit(update_req);
|
||||||
|
ASSERT_TRUE(std::holds_alternative<msgs::CommitResponse>(commit_res));
|
||||||
|
EXPECT_FALSE(std::get<msgs::CommitResponse>(commit_res).error.has_value());
|
||||||
|
}
|
||||||
|
AssertVertexExists(pk, {}, {{primary_property1, primary_key_val}, {prop, msgs::Value(updated_vertex_id)}});
|
||||||
|
|
||||||
|
// Update property prop
|
||||||
|
static constexpr int64_t updated_vertex_id_2{101};
|
||||||
|
{
|
||||||
|
msgs::UpdateVerticesRequest update_req;
|
||||||
|
update_req.transaction_id.logical_id = GetTransactionId();
|
||||||
|
|
||||||
|
update_req.update_vertices =
|
||||||
|
std::vector<msgs::UpdateVertex>{{pk, {}, {}, {{msgs::PropertyId(prop), msgs::Value(updated_vertex_id_2)}}}};
|
||||||
|
|
||||||
|
const auto write_res = shard_rsm->Apply(update_req);
|
||||||
|
ASSERT_TRUE(std::holds_alternative<msgs::UpdateVerticesResponse>(write_res));
|
||||||
|
EXPECT_FALSE(std::get<msgs::UpdateVerticesResponse>(write_res).error.has_value());
|
||||||
|
|
||||||
|
const auto commit_res = Commit(update_req);
|
||||||
|
ASSERT_TRUE(std::holds_alternative<msgs::CommitResponse>(commit_res));
|
||||||
|
EXPECT_FALSE(std::get<msgs::CommitResponse>(commit_res).error.has_value());
|
||||||
|
AssertVertexExists(pk, {}, {{primary_property1, primary_key_val}, {prop, msgs::Value(updated_vertex_id_2)}});
|
||||||
|
}
|
||||||
|
AssertVertexExists(pk, {}, {{primary_property1, primary_key_val}, {prop, msgs::Value(updated_vertex_id_2)}});
|
||||||
|
|
||||||
|
// Remove property prop
|
||||||
|
{
|
||||||
|
msgs::UpdateVerticesRequest update_req;
|
||||||
|
update_req.transaction_id.logical_id = GetTransactionId();
|
||||||
|
|
||||||
|
update_req.update_vertices =
|
||||||
|
std::vector<msgs::UpdateVertex>{{pk, {}, {}, {{msgs::PropertyId(prop), msgs::Value()}}}};
|
||||||
|
|
||||||
|
const auto write_res = shard_rsm->Apply(update_req);
|
||||||
|
ASSERT_TRUE(std::holds_alternative<msgs::UpdateVerticesResponse>(write_res));
|
||||||
|
EXPECT_FALSE(std::get<msgs::UpdateVerticesResponse>(write_res).error.has_value());
|
||||||
|
|
||||||
|
const auto commit_res = Commit(update_req);
|
||||||
|
ASSERT_TRUE(std::holds_alternative<msgs::CommitResponse>(commit_res));
|
||||||
|
EXPECT_FALSE(std::get<msgs::CommitResponse>(commit_res).error.has_value());
|
||||||
|
}
|
||||||
|
AssertVertexExists(pk, {}, {{primary_property1, primary_key_val}});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ShardRSMTest, TestUpdateVertexPrimaryProperty) {
|
||||||
|
const msgs::Value primary_key_val{static_cast<int64_t>(1)};
|
||||||
|
const msgs::PrimaryKey pk{primary_key_val};
|
||||||
|
|
||||||
|
// Create Vertex
|
||||||
|
CreateVertex(pk, {}, {});
|
||||||
|
|
||||||
|
// Try to update primary property
|
||||||
|
static constexpr int64_t updated_vertex_id{10};
|
||||||
|
{
|
||||||
|
msgs::UpdateVerticesRequest update_req;
|
||||||
|
update_req.transaction_id.logical_id = GetTransactionId();
|
||||||
|
|
||||||
|
update_req.update_vertices = std::vector<msgs::UpdateVertex>{
|
||||||
|
{pk, {}, {}, {{msgs::PropertyId(primary_property1), msgs::Value(updated_vertex_id)}}}};
|
||||||
|
|
||||||
|
const auto write_res = shard_rsm->Apply(update_req);
|
||||||
|
ASSERT_TRUE(std::holds_alternative<msgs::UpdateVerticesResponse>(write_res));
|
||||||
|
EXPECT_TRUE(std::get<msgs::UpdateVerticesResponse>(write_res).error.has_value());
|
||||||
|
}
|
||||||
|
AssertVertexExists(pk, {}, {{primary_property1, primary_key_val}});
|
||||||
|
// Try to update primary property of another schema
|
||||||
|
{
|
||||||
|
msgs::UpdateVerticesRequest update_req;
|
||||||
|
update_req.transaction_id.logical_id = GetTransactionId();
|
||||||
|
|
||||||
|
update_req.update_vertices = std::vector<msgs::UpdateVertex>{
|
||||||
|
{pk, {}, {}, {{msgs::PropertyId(primary_property2), msgs::Value(updated_vertex_id)}}}};
|
||||||
|
|
||||||
|
const auto write_res = shard_rsm->Apply(update_req);
|
||||||
|
ASSERT_TRUE(std::holds_alternative<msgs::UpdateVerticesResponse>(write_res));
|
||||||
|
EXPECT_FALSE(std::get<msgs::UpdateVerticesResponse>(write_res).error.has_value());
|
||||||
|
|
||||||
|
const auto commit_res = Commit(update_req);
|
||||||
|
ASSERT_TRUE(std::holds_alternative<msgs::CommitResponse>(commit_res));
|
||||||
|
EXPECT_FALSE(std::get<msgs::CommitResponse>(commit_res).error.has_value());
|
||||||
|
}
|
||||||
|
AssertVertexExists(pk, {},
|
||||||
|
{{primary_property1, primary_key_val}, {primary_property2, msgs::Value(updated_vertex_id)}});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ShardRSMTest, TestUpdateSecondaryLabel) {
|
||||||
|
const msgs::Value primary_key_val{static_cast<int64_t>(1)};
|
||||||
|
const msgs::PrimaryKey pk{primary_key_val};
|
||||||
|
|
||||||
|
// Create Vertex
|
||||||
|
CreateVertex(pk, {}, {});
|
||||||
|
|
||||||
|
// Add label label
|
||||||
|
const msgs::Label secondary_label{label};
|
||||||
|
{
|
||||||
|
msgs::UpdateVerticesRequest update_req;
|
||||||
|
update_req.transaction_id.logical_id = GetTransactionId();
|
||||||
|
|
||||||
|
update_req.update_vertices = std::vector<msgs::UpdateVertex>{{pk, {label}, {}, {}}};
|
||||||
|
|
||||||
|
const auto write_res = shard_rsm->Apply(update_req);
|
||||||
|
ASSERT_TRUE(std::holds_alternative<msgs::UpdateVerticesResponse>(write_res));
|
||||||
|
EXPECT_FALSE(std::get<msgs::UpdateVerticesResponse>(write_res).error.has_value());
|
||||||
|
|
||||||
|
const auto commit_res = Commit(update_req);
|
||||||
|
ASSERT_TRUE(std::holds_alternative<msgs::CommitResponse>(commit_res));
|
||||||
|
EXPECT_FALSE(std::get<msgs::CommitResponse>(commit_res).error.has_value());
|
||||||
|
}
|
||||||
|
AssertVertexExists(pk, {secondary_label}, {{primary_property1, primary_key_val}});
|
||||||
|
|
||||||
|
// Remove primary label
|
||||||
|
{
|
||||||
|
msgs::UpdateVerticesRequest update_req;
|
||||||
|
update_req.transaction_id.logical_id = GetTransactionId();
|
||||||
|
|
||||||
|
update_req.update_vertices = std::vector<msgs::UpdateVertex>{{pk, {}, {label}, {}}};
|
||||||
|
|
||||||
|
const auto write_res = shard_rsm->Apply(update_req);
|
||||||
|
ASSERT_TRUE(std::holds_alternative<msgs::UpdateVerticesResponse>(write_res));
|
||||||
|
EXPECT_FALSE(std::get<msgs::UpdateVerticesResponse>(write_res).error.has_value());
|
||||||
|
|
||||||
|
const auto commit_res = Commit(update_req);
|
||||||
|
ASSERT_TRUE(std::holds_alternative<msgs::CommitResponse>(commit_res));
|
||||||
|
EXPECT_FALSE(std::get<msgs::CommitResponse>(commit_res).error.has_value());
|
||||||
|
}
|
||||||
|
AssertVertexExists(pk, {}, {{primary_property1, primary_key_val}});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ShardRSMTest, TestUpdatePrimaryLabel) {
|
||||||
|
const msgs::Value primary_key_val{static_cast<int64_t>(1)};
|
||||||
|
const msgs::PrimaryKey pk{primary_key_val};
|
||||||
|
|
||||||
|
// Create Vertex
|
||||||
|
CreateVertex(pk, {}, {});
|
||||||
|
|
||||||
|
// Remove primary label
|
||||||
|
{
|
||||||
|
msgs::UpdateVerticesRequest update_req;
|
||||||
|
update_req.transaction_id.logical_id = GetTransactionId();
|
||||||
|
|
||||||
|
update_req.update_vertices = std::vector<msgs::UpdateVertex>{{pk, {}, {primary_label}, {}}};
|
||||||
|
|
||||||
|
const auto write_res = shard_rsm->Apply(update_req);
|
||||||
|
ASSERT_TRUE(std::holds_alternative<msgs::UpdateVerticesResponse>(write_res));
|
||||||
|
EXPECT_TRUE(std::get<msgs::UpdateVerticesResponse>(write_res).error.has_value());
|
||||||
|
}
|
||||||
|
AssertVertexExists(pk, {}, {{primary_property1, primary_key_val}});
|
||||||
|
|
||||||
|
// Add different primary label
|
||||||
|
{
|
||||||
|
msgs::UpdateVerticesRequest update_req;
|
||||||
|
update_req.transaction_id.logical_id = GetTransactionId();
|
||||||
|
|
||||||
|
update_req.update_vertices = std::vector<msgs::UpdateVertex>{{pk, {primary_label2}, {}, {}}};
|
||||||
|
|
||||||
|
const auto write_res = shard_rsm->Apply(update_req);
|
||||||
|
ASSERT_TRUE(std::holds_alternative<msgs::UpdateVerticesResponse>(write_res));
|
||||||
|
EXPECT_TRUE(std::get<msgs::UpdateVerticesResponse>(write_res).error.has_value());
|
||||||
|
}
|
||||||
|
AssertVertexExists(pk, {}, {{primary_property1, primary_key_val}});
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace memgraph::storage::v3::tests
|
@ -16,6 +16,7 @@
|
|||||||
#include <gmock/gmock.h>
|
#include <gmock/gmock.h>
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include "common/errors.hpp"
|
||||||
#include "common/types.hpp"
|
#include "common/types.hpp"
|
||||||
#include "storage/v3/delta.hpp"
|
#include "storage/v3/delta.hpp"
|
||||||
#include "storage/v3/id_types.hpp"
|
#include "storage/v3/id_types.hpp"
|
||||||
@ -76,7 +77,7 @@ TEST_F(StorageV3Accessor, TestPrimaryLabel) {
|
|||||||
ASSERT_TRUE(vertex.PrimaryLabel(View::OLD).HasError());
|
ASSERT_TRUE(vertex.PrimaryLabel(View::OLD).HasError());
|
||||||
const auto error_primary_label = vertex.PrimaryLabel(View::OLD).GetError();
|
const auto error_primary_label = vertex.PrimaryLabel(View::OLD).GetError();
|
||||||
ASSERT_FALSE(vertex.PrimaryLabel(View::NEW).HasError());
|
ASSERT_FALSE(vertex.PrimaryLabel(View::NEW).HasError());
|
||||||
EXPECT_EQ(error_primary_label, Error::NONEXISTENT_OBJECT);
|
EXPECT_EQ(error_primary_label, SHARD_ERROR(ErrorCode::NONEXISTENT_OBJECT));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto acc = storage.Access(GetNextHlc());
|
auto acc = storage.Access(GetNextHlc());
|
||||||
@ -127,9 +128,7 @@ TEST_F(StorageV3Accessor, TestAddLabels) {
|
|||||||
const auto label1 = NameToLabelId("label");
|
const auto label1 = NameToLabelId("label");
|
||||||
auto vertex = acc.CreateVertexAndValidate({label1}, {PropertyValue{2}}, {});
|
auto vertex = acc.CreateVertexAndValidate({label1}, {PropertyValue{2}}, {});
|
||||||
ASSERT_TRUE(vertex.HasError());
|
ASSERT_TRUE(vertex.HasError());
|
||||||
ASSERT_TRUE(std::holds_alternative<SchemaViolation>(vertex.GetError()));
|
EXPECT_EQ(vertex.GetError(), SHARD_ERROR(ErrorCode::SCHEMA_VERTEX_SECONDARY_LABEL_IS_PRIMARY));
|
||||||
EXPECT_EQ(std::get<SchemaViolation>(vertex.GetError()),
|
|
||||||
SchemaViolation(SchemaViolation::ValidationStatus::VERTEX_SECONDARY_LABEL_IS_PRIMARY, label1));
|
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto acc = storage.Access(GetNextHlc());
|
auto acc = storage.Access(GetNextHlc());
|
||||||
@ -138,9 +137,7 @@ TEST_F(StorageV3Accessor, TestAddLabels) {
|
|||||||
ASSERT_TRUE(vertex.HasValue());
|
ASSERT_TRUE(vertex.HasValue());
|
||||||
const auto schema_violation = vertex->AddLabelAndValidate(label1);
|
const auto schema_violation = vertex->AddLabelAndValidate(label1);
|
||||||
ASSERT_TRUE(schema_violation.HasError());
|
ASSERT_TRUE(schema_violation.HasError());
|
||||||
ASSERT_TRUE(std::holds_alternative<SchemaViolation>(schema_violation.GetError()));
|
EXPECT_EQ(schema_violation.GetError(), SHARD_ERROR(ErrorCode::SCHEMA_VERTEX_UPDATE_PRIMARY_LABEL));
|
||||||
EXPECT_EQ(std::get<SchemaViolation>(schema_violation.GetError()),
|
|
||||||
SchemaViolation(SchemaViolation::ValidationStatus::VERTEX_UPDATE_PRIMARY_LABEL, label1));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,9 +181,7 @@ TEST_F(StorageV3Accessor, TestRemoveLabels) {
|
|||||||
auto vertex = CreateVertexAndValidate(acc, {}, PropertyValue{2});
|
auto vertex = CreateVertexAndValidate(acc, {}, PropertyValue{2});
|
||||||
const auto res1 = vertex.RemoveLabelAndValidate(primary_label);
|
const auto res1 = vertex.RemoveLabelAndValidate(primary_label);
|
||||||
ASSERT_TRUE(res1.HasError());
|
ASSERT_TRUE(res1.HasError());
|
||||||
ASSERT_TRUE(std::holds_alternative<SchemaViolation>(res1.GetError()));
|
EXPECT_EQ(res1.GetError(), SHARD_ERROR(ErrorCode::SCHEMA_VERTEX_UPDATE_PRIMARY_LABEL));
|
||||||
EXPECT_EQ(std::get<SchemaViolation>(res1.GetError()),
|
|
||||||
SchemaViolation(SchemaViolation::ValidationStatus::VERTEX_UPDATE_PRIMARY_LABEL, primary_label));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,20 +200,14 @@ TEST_F(StorageV3Accessor, TestSetKeysAndProperties) {
|
|||||||
auto vertex = CreateVertexAndValidate(acc, {}, PropertyValue{1});
|
auto vertex = CreateVertexAndValidate(acc, {}, PropertyValue{1});
|
||||||
const auto res = vertex.SetPropertyAndValidate(primary_property, PropertyValue(1));
|
const auto res = vertex.SetPropertyAndValidate(primary_property, PropertyValue(1));
|
||||||
ASSERT_TRUE(res.HasError());
|
ASSERT_TRUE(res.HasError());
|
||||||
ASSERT_TRUE(std::holds_alternative<SchemaViolation>(res.GetError()));
|
EXPECT_EQ(res.GetError(), SHARD_ERROR(ErrorCode::SCHEMA_VERTEX_UPDATE_PRIMARY_KEY));
|
||||||
EXPECT_EQ(std::get<SchemaViolation>(res.GetError()),
|
|
||||||
SchemaViolation(SchemaViolation::ValidationStatus::VERTEX_UPDATE_PRIMARY_KEY, primary_label,
|
|
||||||
SchemaProperty{primary_property, common::SchemaType::INT}));
|
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto acc = storage.Access(GetNextHlc());
|
auto acc = storage.Access(GetNextHlc());
|
||||||
auto vertex = CreateVertexAndValidate(acc, {}, PropertyValue{2});
|
auto vertex = CreateVertexAndValidate(acc, {}, PropertyValue{2});
|
||||||
const auto res = vertex.SetPropertyAndValidate(primary_property, PropertyValue());
|
const auto res = vertex.SetPropertyAndValidate(primary_property, PropertyValue());
|
||||||
ASSERT_TRUE(res.HasError());
|
ASSERT_TRUE(res.HasError());
|
||||||
ASSERT_TRUE(std::holds_alternative<SchemaViolation>(res.GetError()));
|
EXPECT_EQ(res.GetError(), SHARD_ERROR(ErrorCode::SCHEMA_VERTEX_UPDATE_PRIMARY_KEY));
|
||||||
EXPECT_EQ(std::get<SchemaViolation>(res.GetError()),
|
|
||||||
SchemaViolation(SchemaViolation::ValidationStatus::VERTEX_UPDATE_PRIMARY_KEY, primary_label,
|
|
||||||
SchemaProperty{primary_property, common::SchemaType::INT}));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user