Implement expression evaluator in storage v3 (#534)
- Enable `mg-expr` in mg-storage-v3 - Adapt id_mapper - Change conversion function from PropertyValue to TypedValue - Remove memgraph functions - Enable expression tests on for storage
This commit is contained in:
parent
ecda71168c
commit
817161a915
3
.gitignore
vendored
3
.gitignore
vendored
@ -54,6 +54,7 @@ src/distributed/token_sharing_rpc_messages.hpp
|
||||
src/distributed/updates_rpc_messages.hpp
|
||||
src/query/v2/frontend/ast/ast.hpp
|
||||
src/query/frontend/ast/ast.hpp
|
||||
src/storage/v3/bindings/ast/ast.hpp
|
||||
src/query/distributed/frontend/ast/ast_serialization.hpp
|
||||
src/query/v2/distributed/frontend/ast/ast_serialization.hpp
|
||||
src/durability/distributed/state_delta.hpp
|
||||
@ -67,6 +68,8 @@ src/query/distributed/plan/ops.hpp
|
||||
src/query/v2/distributed/plan/ops.hpp
|
||||
src/query/plan/operator.hpp
|
||||
src/query/v2/plan/operator.hpp
|
||||
src/parser/opencypher/generated
|
||||
src/expr/semantic/symbol.hpp
|
||||
src/raft/log_entry.hpp
|
||||
src/raft/raft_rpc_messages.hpp
|
||||
src/raft/snapshot_metadata.hpp
|
||||
|
@ -32,4 +32,21 @@ class ExpressionRuntimeException : public utils::BasicException {
|
||||
using utils::BasicException::BasicException;
|
||||
};
|
||||
|
||||
class RedeclareVariableError : public SemanticException {
|
||||
public:
|
||||
explicit RedeclareVariableError(const std::string &name) : SemanticException("Redeclaring variable: " + name + ".") {}
|
||||
};
|
||||
|
||||
class UnboundVariableError : public SemanticException {
|
||||
public:
|
||||
explicit UnboundVariableError(const std::string &name) : SemanticException("Unbound variable: " + name + ".") {}
|
||||
};
|
||||
|
||||
class TypeMismatchError : public SemanticException {
|
||||
public:
|
||||
TypeMismatchError(const std::string &name, const std::string &datum, const std::string &expected)
|
||||
: SemanticException(fmt::format("Type mismatch: {} already defined as {}, expected {}.", name, datum, expected)) {
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace memgraph::expr
|
||||
|
@ -28,7 +28,7 @@
|
||||
namespace memgraph::expr {
|
||||
|
||||
template <typename TypedValue, typename EvaluationContext, typename DbAccessor, typename StorageView, typename LabelId,
|
||||
typename PropertyValue, typename ConvFunction, typename Error>
|
||||
typename PropertyValue, typename ConvFunctor, typename Error>
|
||||
class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
|
||||
public:
|
||||
ExpressionEvaluator(Frame<TypedValue> *frame, const SymbolTable &symbol_table, const EvaluationContext &ctx,
|
||||
@ -719,7 +719,7 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
|
||||
throw ExpressionRuntimeException("Unexpected error when getting a property.");
|
||||
}
|
||||
}
|
||||
return conv_(*maybe_prop);
|
||||
return conv_(*maybe_prop, ctx_->memory);
|
||||
}
|
||||
|
||||
template <class TRecordAccessor>
|
||||
@ -746,7 +746,7 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
|
||||
throw ExpressionRuntimeException("Unexpected error when getting a property.");
|
||||
}
|
||||
}
|
||||
return conv_(*maybe_prop);
|
||||
return conv_(*maybe_prop, ctx_->memory);
|
||||
}
|
||||
|
||||
LabelId GetLabel(LabelIx label) { return ctx_->labels[label.ix]; }
|
||||
@ -757,7 +757,7 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
|
||||
DbAccessor *dba_;
|
||||
// which switching approach should be used when evaluating
|
||||
StorageView view_;
|
||||
ConvFunction conv_;
|
||||
ConvFunctor conv_;
|
||||
};
|
||||
|
||||
/// A helper function for evaluating an expression that's an int.
|
||||
|
@ -17,18 +17,24 @@
|
||||
#include "query/v2/bindings/typed_value.hpp"
|
||||
#include "query/v2/context.hpp"
|
||||
#include "query/v2/db_accessor.hpp"
|
||||
#include "storage/v3/conversions.hpp"
|
||||
#include "storage/v3/id_types.hpp"
|
||||
#include "storage/v3/property_store.hpp"
|
||||
#include "storage/v3/view.hpp"
|
||||
#include "storage/v3/conversions.hpp"
|
||||
|
||||
namespace memgraph::query::v2 {
|
||||
|
||||
inline const auto lam = [](const auto &val) { return memgraph::storage::v3::PropertyToTypedValue<TypedValue>(val); };
|
||||
struct PropertyToTypedValueConverter {
|
||||
TypedValue operator()(const auto &val) { return memgraph::storage::v3::PropertyToTypedValue<TypedValue>(val); }
|
||||
|
||||
TypedValue operator()(const auto &val, utils::MemoryResource *mem) {
|
||||
return memgraph::storage::v3::PropertyToTypedValue<TypedValue>(val, mem);
|
||||
}
|
||||
};
|
||||
|
||||
using ExpressionEvaluator =
|
||||
memgraph::expr::ExpressionEvaluator<TypedValue, EvaluationContext, DbAccessor, storage::v3::View,
|
||||
storage::v3::LabelId, storage::v3::PropertyStore, decltype(lam),
|
||||
storage::v3::LabelId, storage::v3::PropertyStore, PropertyToTypedValueConverter,
|
||||
memgraph::storage::v3::Error>;
|
||||
|
||||
} // namespace memgraph::query::v2
|
||||
|
@ -360,17 +360,13 @@ class DbAccessor final {
|
||||
// TODO(jbajic) Query engine should have a map of labels, properties and edge
|
||||
// types
|
||||
// NOLINTNEXTLINE(readability-convert-member-functions-to-static)
|
||||
storage::v3::PropertyId NameToProperty(const std::string_view /*name*/) {
|
||||
return storage::v3::PropertyId::FromUint(0);
|
||||
}
|
||||
storage::v3::PropertyId NameToProperty(const std::string_view name) { return accessor_->NameToProperty(name); }
|
||||
|
||||
// NOLINTNEXTLINE(readability-convert-member-functions-to-static)
|
||||
storage::v3::LabelId NameToLabel(const std::string_view /*name*/) { return storage::v3::LabelId::FromUint(0); }
|
||||
storage::v3::LabelId NameToLabel(const std::string_view name) { return accessor_->NameToLabel(name); }
|
||||
|
||||
// NOLINTNEXTLINE(readability-convert-member-functions-to-static)
|
||||
storage::v3::EdgeTypeId NameToEdgeType(const std::string_view /*name*/) {
|
||||
return storage::v3::EdgeTypeId::FromUint(0);
|
||||
}
|
||||
storage::v3::EdgeTypeId NameToEdgeType(const std::string_view name) { return accessor_->NameToEdgeType(name); }
|
||||
|
||||
const std::string &PropertyToName(storage::v3::PropertyId prop) const { return accessor_->PropertyToName(prop); }
|
||||
|
||||
|
@ -960,7 +960,6 @@ Callback HandleSchemaQuery(SchemaQuery *schema_query, InterpreterContext *interp
|
||||
callback.fn = [interpreter_context, primary_label = schema_query->label_]() {
|
||||
auto *db = interpreter_context->db;
|
||||
const auto label = interpreter_context->NameToLabelId(primary_label.name);
|
||||
|
||||
if (!db->DropSchema(label)) {
|
||||
throw QueryException(fmt::format("Schema on label :{} does not exist!", primary_label.name));
|
||||
}
|
||||
@ -1431,7 +1430,7 @@ PreparedQuery PrepareIndexQuery(ParsedQuery parsed_query, bool in_explicit_trans
|
||||
}
|
||||
};
|
||||
|
||||
auto label = interpreter_context->NameToLabelId(index_query->label_.name);
|
||||
const auto label = interpreter_context->NameToLabelId(index_query->label_.name);
|
||||
|
||||
std::vector<storage::v3::PropertyId> properties;
|
||||
std::vector<std::string> properties_string;
|
||||
@ -1998,7 +1997,7 @@ PreparedQuery PrepareConstraintQuery(ParsedQuery parsed_query, bool in_explicit_
|
||||
auto *constraint_query = utils::Downcast<ConstraintQuery>(parsed_query.query);
|
||||
std::function<void(Notification &)> handler;
|
||||
|
||||
auto label = interpreter_context->NameToLabelId(constraint_query->constraint_.label.name);
|
||||
const auto label = interpreter_context->NameToLabelId(constraint_query->constraint_.label.name);
|
||||
std::vector<storage::v3::PropertyId> properties;
|
||||
std::vector<std::string> properties_string;
|
||||
properties.reserve(constraint_query->constraint_.properties.size());
|
||||
|
@ -1,4 +1,11 @@
|
||||
define_add_lcp(add_storage_ast lcp_storage_v3_cpp_files generated_lcp_storage_v3_files)
|
||||
|
||||
add_storage_ast(bindings/ast/ast.lcp)
|
||||
|
||||
add_custom_target(generate_lcp_ast_storage_v3 DEPENDS ${generated_lcp_storage_v3_files})
|
||||
|
||||
set(storage_v3_src_files
|
||||
${lcp_storage_v3_cpp_files}
|
||||
commit_log.cpp
|
||||
constraints.cpp
|
||||
temporal.cpp
|
||||
@ -15,8 +22,9 @@ set(storage_v3_src_files
|
||||
schemas.cpp
|
||||
schema_validator.cpp
|
||||
shard.cpp
|
||||
storage.cpp
|
||||
shard_rsm.cpp)
|
||||
bindings/typed_value.cpp
|
||||
shard_rsm.cpp
|
||||
storage.cpp)
|
||||
|
||||
# #### Replication #####
|
||||
define_add_lcp(add_lcp_storage lcp_storage_cpp_files generated_lcp_storage_files)
|
||||
@ -38,7 +46,9 @@ find_package(gflags REQUIRED)
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
add_library(mg-storage-v3 STATIC ${storage_v3_src_files})
|
||||
add_dependencies(mg-storage-v3 generate_lcp_ast_storage_v3)
|
||||
target_link_libraries(mg-storage-v3 Threads::Threads mg-utils gflags)
|
||||
target_include_directories(mg-storage-v3 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/bindings)
|
||||
|
||||
add_dependencies(mg-storage-v3 generate_lcp_storage)
|
||||
target_link_libraries(mg-storage-v3 mg-rpc mg-slk mg-expr)
|
||||
|
2724
src/storage/v3/bindings/ast/ast.lcp
Normal file
2724
src/storage/v3/bindings/ast/ast.lcp
Normal file
File diff suppressed because it is too large
Load Diff
16
src/storage/v3/bindings/ast_visitor.hpp
Normal file
16
src/storage/v3/bindings/ast_visitor.hpp
Normal file
@ -0,0 +1,16 @@
|
||||
// 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 "storage/v3/bindings/bindings.hpp"
|
||||
|
||||
#include "expr/ast/ast_visitor.hpp"
|
15
src/storage/v3/bindings/bindings.hpp
Normal file
15
src/storage/v3/bindings/bindings.hpp
Normal file
@ -0,0 +1,15 @@
|
||||
// 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
|
||||
|
||||
#define MG_AST_INCLUDE_PATH "storage/v3/bindings/ast/ast.hpp" // NOLINT(cppcoreguidelines-macro-usage)
|
||||
#define MG_INJECTED_NAMESPACE_NAME memgraph::storage::v3 // NOLINT(cppcoreguidelines-macro-usage)
|
20
src/storage/v3/bindings/cypher_main_visitor.hpp
Normal file
20
src/storage/v3/bindings/cypher_main_visitor.hpp
Normal file
@ -0,0 +1,20 @@
|
||||
// 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 "storage/v3/bindings/bindings.hpp"
|
||||
|
||||
#include "expr/ast/cypher_main_visitor.hpp"
|
||||
|
||||
namespace memgraph::storage::v3 {
|
||||
using CypherMainVisitor = memgraph::expr::CypherMainVisitor;
|
||||
} // namespace memgraph::storage::v3
|
209
src/storage/v3/bindings/db_accessor.hpp
Normal file
209
src/storage/v3/bindings/db_accessor.hpp
Normal file
@ -0,0 +1,209 @@
|
||||
// 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 "storage/v3/shard.hpp"
|
||||
|
||||
namespace memgraph::storage::v3 {
|
||||
|
||||
class DbAccessor final {
|
||||
Shard::Accessor *accessor_;
|
||||
|
||||
class VerticesIterable final {
|
||||
storage::v3::VerticesIterable iterable_;
|
||||
|
||||
public:
|
||||
class Iterator final {
|
||||
storage::v3::VerticesIterable::Iterator it_;
|
||||
|
||||
public:
|
||||
explicit Iterator(storage::v3::VerticesIterable::Iterator it) : it_(it) {}
|
||||
|
||||
VertexAccessor operator*() const { return VertexAccessor(*it_); }
|
||||
|
||||
Iterator &operator++() {
|
||||
++it_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const Iterator &other) const { return it_ == other.it_; }
|
||||
|
||||
bool operator!=(const Iterator &other) const { return !(other == *this); }
|
||||
};
|
||||
|
||||
explicit VerticesIterable(storage::v3::VerticesIterable iterable) : iterable_(std::move(iterable)) {}
|
||||
|
||||
Iterator begin() { return Iterator(iterable_.begin()); }
|
||||
|
||||
Iterator end() { return Iterator(iterable_.end()); }
|
||||
};
|
||||
|
||||
public:
|
||||
explicit DbAccessor(storage::v3::Shard::Accessor *accessor) : accessor_(accessor) {}
|
||||
|
||||
// TODO(jbajic) Fix Remove Gid
|
||||
// NOLINTNEXTLINE(readability-convert-member-functions-to-static)
|
||||
std::optional<VertexAccessor> FindVertex(uint64_t /*unused*/) { return std::nullopt; }
|
||||
|
||||
std::optional<VertexAccessor> FindVertex(storage::v3::PrimaryKey &primary_key, storage::v3::View view) {
|
||||
auto maybe_vertex = accessor_->FindVertex(primary_key, view);
|
||||
if (maybe_vertex) return VertexAccessor(*maybe_vertex);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void FinalizeTransaction() { accessor_->FinalizeTransaction(); }
|
||||
|
||||
VerticesIterable Vertices(storage::v3::View view) { return VerticesIterable(accessor_->Vertices(view)); }
|
||||
|
||||
VerticesIterable Vertices(storage::v3::View view, storage::v3::LabelId label) {
|
||||
return VerticesIterable(accessor_->Vertices(label, view));
|
||||
}
|
||||
|
||||
VerticesIterable Vertices(storage::v3::View view, storage::v3::LabelId label, storage::v3::PropertyId property) {
|
||||
return VerticesIterable(accessor_->Vertices(label, property, view));
|
||||
}
|
||||
|
||||
VerticesIterable Vertices(storage::v3::View view, storage::v3::LabelId label, storage::v3::PropertyId property,
|
||||
const storage::v3::PropertyValue &value) {
|
||||
return VerticesIterable(accessor_->Vertices(label, property, value, view));
|
||||
}
|
||||
|
||||
VerticesIterable Vertices(storage::v3::View view, storage::v3::LabelId label, storage::v3::PropertyId property,
|
||||
const std::optional<utils::Bound<storage::v3::PropertyValue>> &lower,
|
||||
const std::optional<utils::Bound<storage::v3::PropertyValue>> &upper) {
|
||||
return VerticesIterable(accessor_->Vertices(label, property, lower, upper, view));
|
||||
}
|
||||
|
||||
storage::v3::ResultSchema<VertexAccessor> InsertVertexAndValidate(
|
||||
const storage::v3::LabelId primary_label, const std::vector<storage::v3::LabelId> &labels,
|
||||
const std::vector<std::pair<storage::v3::PropertyId, storage::v3::PropertyValue>> &properties) {
|
||||
auto maybe_vertex_acc = accessor_->CreateVertexAndValidate(primary_label, labels, properties);
|
||||
if (maybe_vertex_acc.HasError()) {
|
||||
return {std::move(maybe_vertex_acc.GetError())};
|
||||
}
|
||||
return VertexAccessor{maybe_vertex_acc.GetValue()};
|
||||
}
|
||||
|
||||
storage::v3::Result<EdgeAccessor> InsertEdge(VertexAccessor *from, VertexAccessor *to,
|
||||
const storage::v3::EdgeTypeId &edge_type) {
|
||||
static constexpr auto kDummyGid = storage::v3::Gid::FromUint(0);
|
||||
auto maybe_edge = accessor_->CreateEdge(from->Id(storage::v3::View::NEW).GetValue(),
|
||||
to->Id(storage::v3::View::NEW).GetValue(), edge_type, kDummyGid);
|
||||
if (maybe_edge.HasError()) return {maybe_edge.GetError()};
|
||||
return EdgeAccessor(*maybe_edge);
|
||||
}
|
||||
|
||||
storage::v3::Result<std::optional<EdgeAccessor>> RemoveEdge(EdgeAccessor *edge) {
|
||||
auto res = accessor_->DeleteEdge(edge->FromVertex(), edge->ToVertex(), edge->Gid());
|
||||
if (res.HasError()) {
|
||||
return res.GetError();
|
||||
}
|
||||
|
||||
const auto &value = res.GetValue();
|
||||
if (!value) {
|
||||
return std::optional<EdgeAccessor>{};
|
||||
}
|
||||
|
||||
return std::make_optional<EdgeAccessor>(*value);
|
||||
}
|
||||
|
||||
storage::v3::Result<std::optional<std::pair<VertexAccessor, std::vector<EdgeAccessor>>>> DetachRemoveVertex(
|
||||
VertexAccessor *vertex_accessor) {
|
||||
using ReturnType = std::pair<VertexAccessor, std::vector<EdgeAccessor>>;
|
||||
|
||||
auto res = accessor_->DetachDeleteVertex(vertex_accessor);
|
||||
if (res.HasError()) {
|
||||
return res.GetError();
|
||||
}
|
||||
|
||||
const auto &value = res.GetValue();
|
||||
if (!value) {
|
||||
return std::optional<ReturnType>{};
|
||||
}
|
||||
|
||||
const auto &[vertex, edges] = *value;
|
||||
|
||||
std::vector<EdgeAccessor> deleted_edges;
|
||||
deleted_edges.reserve(edges.size());
|
||||
std::transform(edges.begin(), edges.end(), std::back_inserter(deleted_edges),
|
||||
[](const auto &deleted_edge) { return EdgeAccessor{deleted_edge}; });
|
||||
|
||||
return std::make_optional<ReturnType>(vertex, std::move(deleted_edges));
|
||||
}
|
||||
|
||||
storage::v3::Result<std::optional<VertexAccessor>> RemoveVertex(VertexAccessor *vertex_accessor) {
|
||||
auto res = accessor_->DeleteVertex(vertex_accessor);
|
||||
if (res.HasError()) {
|
||||
return res.GetError();
|
||||
}
|
||||
|
||||
const auto &value = res.GetValue();
|
||||
if (!value) {
|
||||
return std::optional<VertexAccessor>{};
|
||||
}
|
||||
|
||||
return {std::make_optional<VertexAccessor>(*value)};
|
||||
}
|
||||
|
||||
storage::v3::LabelId NameToLabel(const std::string_view name) { return accessor_->NameToLabel(name); }
|
||||
|
||||
storage::v3::PropertyId NameToProperty(const std::string_view name) { return accessor_->NameToProperty(name); }
|
||||
|
||||
// NOLINTNEXTLINE(readability-convert-member-functions-to-static)
|
||||
storage::v3::EdgeTypeId NameToEdgeType(const std::string_view name) { return accessor_->NameToEdgeType(name); }
|
||||
|
||||
const std::string &PropertyToName(storage::v3::PropertyId prop) const { return accessor_->PropertyToName(prop); }
|
||||
|
||||
const std::string &LabelToName(storage::v3::LabelId label) const { return accessor_->LabelToName(label); }
|
||||
|
||||
const std::string &EdgeTypeToName(storage::v3::EdgeTypeId type) const { return accessor_->EdgeTypeToName(type); }
|
||||
|
||||
void AdvanceCommand() { accessor_->AdvanceCommand(); }
|
||||
|
||||
utils::BasicResult<storage::v3::ConstraintViolation, void> Commit() { return accessor_->Commit(); }
|
||||
|
||||
void Abort() { accessor_->Abort(); }
|
||||
|
||||
bool LabelIndexExists(storage::v3::LabelId label) const { return accessor_->LabelIndexExists(label); }
|
||||
|
||||
bool LabelPropertyIndexExists(storage::v3::LabelId label, storage::v3::PropertyId prop) const {
|
||||
return accessor_->LabelPropertyIndexExists(label, prop);
|
||||
}
|
||||
|
||||
int64_t VerticesCount() const { return accessor_->ApproximateVertexCount(); }
|
||||
|
||||
int64_t VerticesCount(storage::v3::LabelId label) const { return accessor_->ApproximateVertexCount(label); }
|
||||
|
||||
int64_t VerticesCount(storage::v3::LabelId label, storage::v3::PropertyId property) const {
|
||||
return accessor_->ApproximateVertexCount(label, property);
|
||||
}
|
||||
|
||||
int64_t VerticesCount(storage::v3::LabelId label, storage::v3::PropertyId property,
|
||||
const storage::v3::PropertyValue &value) const {
|
||||
return accessor_->ApproximateVertexCount(label, property, value);
|
||||
}
|
||||
|
||||
int64_t VerticesCount(storage::v3::LabelId label, storage::v3::PropertyId property,
|
||||
const std::optional<utils::Bound<storage::v3::PropertyValue>> &lower,
|
||||
const std::optional<utils::Bound<storage::v3::PropertyValue>> &upper) const {
|
||||
return accessor_->ApproximateVertexCount(label, property, lower, upper);
|
||||
}
|
||||
|
||||
storage::v3::IndicesInfo ListAllIndices() const { return accessor_->ListAllIndices(); }
|
||||
|
||||
storage::v3::ConstraintsInfo ListAllConstraints() const { return accessor_->ListAllConstraints(); }
|
||||
|
||||
const storage::v3::SchemaValidator &GetSchemaValidator() const { return accessor_->GetSchemaValidator(); }
|
||||
|
||||
storage::v3::SchemasInfo ListAllSchemas() const { return accessor_->ListAllSchemas(); }
|
||||
};
|
||||
} // namespace memgraph::storage::v3
|
104
src/storage/v3/bindings/eval.hpp
Normal file
104
src/storage/v3/bindings/eval.hpp
Normal file
@ -0,0 +1,104 @@
|
||||
// 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 "storage/v2/property_value.hpp"
|
||||
#include "storage/v3/bindings/bindings.hpp"
|
||||
|
||||
#include "expr/interpret/eval.hpp"
|
||||
#include "storage/v3/bindings/db_accessor.hpp"
|
||||
#include "storage/v3/bindings/typed_value.hpp"
|
||||
#include "storage/v3/conversions.hpp"
|
||||
#include "storage/v3/id_types.hpp"
|
||||
#include "storage/v3/property_store.hpp"
|
||||
#include "storage/v3/property_value.hpp"
|
||||
#include "storage/v3/view.hpp"
|
||||
#include "utils/memory.hpp"
|
||||
|
||||
namespace memgraph::storage::v3 {
|
||||
|
||||
struct PropertyToTypedValueConverter {
|
||||
TypedValue operator()(const auto &val) { return memgraph::storage::v3::PropertyToTypedValue<TypedValue>(val); }
|
||||
|
||||
TypedValue operator()(const auto &val, utils::MemoryResource *mem) {
|
||||
return memgraph::storage::v3::PropertyToTypedValue<TypedValue>(val, mem);
|
||||
}
|
||||
};
|
||||
|
||||
struct Parameters {
|
||||
public:
|
||||
/**
|
||||
* Adds a value to the stripped arguments under a token position.
|
||||
*
|
||||
* @param position Token position in query of value.
|
||||
* @param value
|
||||
*/
|
||||
void Add(int position, const storage::v3::PropertyValue &value) { storage_.emplace_back(position, value); }
|
||||
|
||||
/**
|
||||
* Returns the value found for the given token position.
|
||||
*
|
||||
* @param position Token position in query of value.
|
||||
* @return Value for the given token position.
|
||||
*/
|
||||
const storage::v3::PropertyValue &AtTokenPosition(int position) const {
|
||||
auto found = std::find_if(storage_.begin(), storage_.end(), [&](const auto &a) { return a.first == position; });
|
||||
MG_ASSERT(found != storage_.end(), "Token position must be present in container");
|
||||
return found->second;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the position-th stripped value. Asserts that this
|
||||
* container has at least (position + 1) elements.
|
||||
*
|
||||
* @param position Which stripped param is sought.
|
||||
* @return Token position and value for sought param.
|
||||
*/
|
||||
const std::pair<int, storage::v3::PropertyValue> &At(int position) const {
|
||||
MG_ASSERT(position < static_cast<int>(storage_.size()), "Invalid position");
|
||||
return storage_[position];
|
||||
}
|
||||
|
||||
/** Returns the number of arguments in this container */
|
||||
auto size() const { return storage_.size(); }
|
||||
|
||||
auto begin() const { return storage_.begin(); }
|
||||
auto end() const { return storage_.end(); }
|
||||
|
||||
private:
|
||||
std::vector<std::pair<int, storage::v3::PropertyValue>> storage_;
|
||||
};
|
||||
|
||||
struct EvaluationContext {
|
||||
/// Memory for allocations during evaluation of a *single* Pull call.
|
||||
///
|
||||
/// Although the assigned memory may live longer than the duration of a Pull
|
||||
/// (e.g. memory is the same as the whole execution memory), you have to treat
|
||||
/// it as if the lifetime is only valid during the Pull.
|
||||
utils::MemoryResource *memory{utils::NewDeleteResource()};
|
||||
int64_t timestamp{-1};
|
||||
Parameters parameters;
|
||||
/// All properties indexable via PropertyIx
|
||||
std::vector<storage::v3::PropertyId> properties;
|
||||
/// All labels indexable via LabelIx
|
||||
std::vector<storage::v3::LabelId> labels;
|
||||
/// All counters generated by `counter` function, mutable because the function
|
||||
/// modifies the values
|
||||
mutable std::unordered_map<std::string, int64_t> counters;
|
||||
};
|
||||
|
||||
using ExpressionEvaluator =
|
||||
memgraph::expr::ExpressionEvaluator<TypedValue, EvaluationContext, DbAccessor, storage::v3::View,
|
||||
storage::v3::LabelId, storage::v3::PropertyStore, PropertyToTypedValueConverter,
|
||||
memgraph::storage::v3::Error>;
|
||||
|
||||
} // namespace memgraph::storage::v3
|
21
src/storage/v3/bindings/frame.hpp
Normal file
21
src/storage/v3/bindings/frame.hpp
Normal file
@ -0,0 +1,21 @@
|
||||
// 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 "storage/v3/bindings/bindings.hpp"
|
||||
|
||||
#include "expr/interpret/frame.hpp"
|
||||
#include "storage/v3/bindings/typed_value.hpp"
|
||||
|
||||
namespace memgraph::storage::v3 {
|
||||
using Frame = memgraph::expr::Frame<TypedValue>;
|
||||
} // namespace memgraph::storage::v3
|
18
src/storage/v3/bindings/pretty_print.hpp
Normal file
18
src/storage/v3/bindings/pretty_print.hpp
Normal file
@ -0,0 +1,18 @@
|
||||
// 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 "storage/v3/bindings/bindings.hpp"
|
||||
|
||||
#include "expr/ast/pretty_print.hpp"
|
||||
|
||||
namespace memgraph::storage::v3 {} // namespace memgraph::storage::v3
|
20
src/storage/v3/bindings/symbol.hpp
Normal file
20
src/storage/v3/bindings/symbol.hpp
Normal file
@ -0,0 +1,20 @@
|
||||
// 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 "storage/v3/bindings/bindings.hpp"
|
||||
|
||||
#include "expr/semantic/symbol.hpp"
|
||||
|
||||
namespace memgraph::storage::v3 {
|
||||
using Symbol = memgraph::expr::Symbol;
|
||||
} // namespace memgraph::storage::v3
|
16
src/storage/v3/bindings/symbol_generator.hpp
Normal file
16
src/storage/v3/bindings/symbol_generator.hpp
Normal file
@ -0,0 +1,16 @@
|
||||
// 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 "storage/v3/bindings/bindings.hpp"
|
||||
|
||||
#include "expr/semantic/symbol_generator.hpp"
|
20
src/storage/v3/bindings/symbol_table.hpp
Normal file
20
src/storage/v3/bindings/symbol_table.hpp
Normal file
@ -0,0 +1,20 @@
|
||||
// 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 "storage/v3/bindings/bindings.hpp"
|
||||
|
||||
#include "expr/semantic/symbol_table.hpp"
|
||||
|
||||
namespace memgraph::storage::v3 {
|
||||
using SymbolTable = memgraph::expr::SymbolTable;
|
||||
} // namespace memgraph::storage::v3
|
23
src/storage/v3/bindings/typed_value.cpp
Normal file
23
src/storage/v3/bindings/typed_value.cpp
Normal file
@ -0,0 +1,23 @@
|
||||
// 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 "expr/typed_value.hpp"
|
||||
|
||||
#include "storage/v3/edge_accessor.hpp"
|
||||
#include "storage/v3/path.hpp"
|
||||
#include "storage/v3/vertex_accessor.hpp"
|
||||
|
||||
namespace memgraph::expr {
|
||||
|
||||
namespace v3 = memgraph::storage::v3;
|
||||
template class TypedValueT<v3::VertexAccessor, v3::EdgeAccessor, v3::Path>;
|
||||
|
||||
} // namespace memgraph::expr
|
28
src/storage/v3/bindings/typed_value.hpp
Normal file
28
src/storage/v3/bindings/typed_value.hpp
Normal file
@ -0,0 +1,28 @@
|
||||
// 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 "expr/typed_value.hpp"
|
||||
|
||||
#include "storage/v3/bindings/bindings.hpp"
|
||||
#include "storage/v3/edge_accessor.hpp"
|
||||
#include "storage/v3/path.hpp"
|
||||
#include "storage/v3/vertex_accessor.hpp"
|
||||
|
||||
namespace memgraph::expr {
|
||||
namespace v3 = memgraph::storage::v3;
|
||||
extern template class memgraph::expr::TypedValueT<v3::VertexAccessor, v3::EdgeAccessor, v3::Path>;
|
||||
} // namespace memgraph::expr
|
||||
|
||||
namespace memgraph::storage::v3 {
|
||||
using TypedValue = memgraph::expr::TypedValueT<VertexAccessor, EdgeAccessor, Path>;
|
||||
} // namespace memgraph::storage::v3
|
@ -11,6 +11,7 @@
|
||||
|
||||
#include "expr/typed_value.hpp"
|
||||
#include "storage/v3/property_value.hpp"
|
||||
#include "utils/memory.hpp"
|
||||
|
||||
#pragma once
|
||||
|
||||
@ -67,6 +68,57 @@ TTypedValue PropertyToTypedValue(const PropertyValue &value) {
|
||||
LOG_FATAL("Unsupported type");
|
||||
}
|
||||
|
||||
template <typename TTypedValue>
|
||||
TTypedValue PropertyToTypedValue(const PropertyValue &value, utils::MemoryResource *mem) {
|
||||
switch (value.type()) {
|
||||
case storage::v3::PropertyValue::Type::Null:
|
||||
return TTypedValue(mem);
|
||||
case storage::v3::PropertyValue::Type::Bool:
|
||||
return TTypedValue(value.ValueBool(), mem);
|
||||
case storage::v3::PropertyValue::Type::Int:
|
||||
return TTypedValue(value.ValueInt(), mem);
|
||||
case storage::v3::PropertyValue::Type::Double:
|
||||
return TTypedValue(value.ValueDouble(), mem);
|
||||
case storage::v3::PropertyValue::Type::String:
|
||||
return TTypedValue(value.ValueString(), mem);
|
||||
case storage::v3::PropertyValue::Type::List: {
|
||||
const auto &src = value.ValueList();
|
||||
std::vector<TTypedValue> dst;
|
||||
dst.reserve(src.size());
|
||||
for (const auto &elem : src) {
|
||||
dst.push_back(PropertyToTypedValue<TTypedValue>(elem, mem));
|
||||
}
|
||||
return TTypedValue(std::move(dst), mem);
|
||||
}
|
||||
case storage::v3::PropertyValue::Type::Map: {
|
||||
const auto &src = value.ValueMap();
|
||||
std::map<std::string, TTypedValue> dst;
|
||||
for (const auto &elem : src) {
|
||||
dst.insert({std::string(elem.first), PropertyToTypedValue<TTypedValue>(elem.second, mem)});
|
||||
}
|
||||
return TTypedValue(std::move(dst), mem);
|
||||
}
|
||||
case storage::v3::PropertyValue::Type::TemporalData: {
|
||||
const auto &temporal_data = value.ValueTemporalData();
|
||||
switch (temporal_data.type) {
|
||||
case storage::v3::TemporalType::Date: {
|
||||
return TTypedValue(utils::Date(temporal_data.microseconds), mem);
|
||||
}
|
||||
case storage::v3::TemporalType::LocalTime: {
|
||||
return TTypedValue(utils::LocalTime(temporal_data.microseconds), mem);
|
||||
}
|
||||
case storage::v3::TemporalType::LocalDateTime: {
|
||||
return TTypedValue(utils::LocalDateTime(temporal_data.microseconds), mem);
|
||||
}
|
||||
case storage::v3::TemporalType::Duration: {
|
||||
return TTypedValue(utils::Duration(temporal_data.microseconds), mem);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
LOG_FATAL("Unsupported type");
|
||||
}
|
||||
|
||||
template <typename TTypedValue>
|
||||
storage::v3::PropertyValue TypedToPropertyValue(const TTypedValue &value) {
|
||||
switch (value.type()) {
|
||||
|
@ -220,6 +220,7 @@ struct Delta {
|
||||
case Action::REMOVE_IN_EDGE:
|
||||
case Action::REMOVE_OUT_EDGE:
|
||||
std::destroy_at(&vertex_edge.vertex_id);
|
||||
break;
|
||||
case Action::SET_PROPERTY:
|
||||
property.value.~PropertyValue();
|
||||
break;
|
||||
|
@ -92,6 +92,10 @@ Result<std::map<PropertyId, PropertyValue>> EdgeAccessor::ClearProperties() {
|
||||
return std::move(properties);
|
||||
}
|
||||
|
||||
Result<PropertyValue> EdgeAccessor::GetProperty(View view, PropertyId property) const {
|
||||
return GetProperty(property, view);
|
||||
}
|
||||
|
||||
Result<PropertyValue> EdgeAccessor::GetProperty(PropertyId property, View view) const {
|
||||
if (!config_.properties_on_edges) return PropertyValue();
|
||||
auto exists = true;
|
||||
|
@ -67,6 +67,8 @@ class EdgeAccessor final {
|
||||
/// @throw std::bad_alloc
|
||||
Result<PropertyValue> GetProperty(PropertyId property, View view) const;
|
||||
|
||||
Result<PropertyValue> GetProperty(View view, PropertyId property) const;
|
||||
|
||||
/// @throw std::bad_alloc
|
||||
Result<std::map<PropertyId, PropertyValue>> Properties(View view) const;
|
||||
|
||||
|
@ -11,9 +11,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "utils/logging.hpp"
|
||||
#include "utils/skip_list.hpp"
|
||||
@ -21,78 +23,47 @@
|
||||
namespace memgraph::storage::v3 {
|
||||
|
||||
class NameIdMapper final {
|
||||
private:
|
||||
struct MapNameToId {
|
||||
std::string name;
|
||||
uint64_t id;
|
||||
|
||||
bool operator<(const MapNameToId &other) const { return name < other.name; }
|
||||
bool operator==(const MapNameToId &other) const { return name == other.name; }
|
||||
|
||||
bool operator<(const std::string_view &other) const { return name < other; }
|
||||
bool operator==(const std::string_view &other) const { return name == other; }
|
||||
};
|
||||
|
||||
struct MapIdToName {
|
||||
uint64_t id;
|
||||
std::string name;
|
||||
|
||||
bool operator<(const MapIdToName &other) const { return id < other.id; }
|
||||
bool operator==(const MapIdToName &other) const { return id == other.id; }
|
||||
|
||||
bool operator<(uint64_t other) const { return id < other; }
|
||||
bool operator==(uint64_t other) const { return id == other; }
|
||||
};
|
||||
|
||||
public:
|
||||
/// @throw std::bad_alloc if unable to insert a new mapping
|
||||
uint64_t NameToId(const std::string_view &name) {
|
||||
auto name_to_id_acc = name_to_id_.access();
|
||||
auto found = name_to_id_acc.find(name);
|
||||
uint64_t id{0};
|
||||
if (found == name_to_id_acc.end()) {
|
||||
uint64_t new_id = counter_.fetch_add(1, std::memory_order_acq_rel);
|
||||
// Try to insert the mapping with the `new_id`, but use the id that is in
|
||||
// the object itself. The object that cointains the mapping is designed to
|
||||
// be a map, so that if the inserted name already exists `insert` will
|
||||
// return an iterator to the existing item. This prevents assignment of
|
||||
// two IDs to the same name when the mapping is being inserted
|
||||
// concurrently from two threads. One ID is wasted in that case, though.
|
||||
id = name_to_id_acc.insert({std::string(name), new_id}).first->id;
|
||||
} else {
|
||||
id = found->id;
|
||||
static constexpr uint64_t kUnmappedId{0};
|
||||
NameIdMapper() = default;
|
||||
|
||||
explicit NameIdMapper(std::unordered_map<uint64_t, std::string> id_to_name) : id_to_name_{std::move(id_to_name)} {
|
||||
for (const auto &[id, name] : id_to_name_) {
|
||||
name_to_id_.emplace(name, id);
|
||||
}
|
||||
auto id_to_name_acc = id_to_name_.access();
|
||||
// We have to try to insert the ID to name mapping even if we are not the
|
||||
// one who assigned the ID because we have to make sure that after this
|
||||
// method returns that both mappings exist.
|
||||
if (id_to_name_acc.find(id) == id_to_name_acc.end()) {
|
||||
// We first try to find the `id` in the map to avoid making an unnecessary
|
||||
// temporary memory allocation when the object already exists.
|
||||
id_to_name_acc.insert({id, std::string(name)});
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
// NOTE: Currently this function returns a `const std::string &` instead of a
|
||||
// `std::string` to avoid making unnecessary copies of the string.
|
||||
// Usually, this wouldn't be correct because the accessor to the
|
||||
// `utils::SkipList` is destroyed in this function and that removes the
|
||||
// guarantee that the reference to the value contained in the list will be
|
||||
// valid.
|
||||
// Currently, we never delete anything from the `utils::SkipList` so the
|
||||
// references will always be valid. If you change this class to remove unused
|
||||
// names, be sure to change the signature of this function.
|
||||
const std::string &IdToName(uint64_t id) const {
|
||||
auto id_to_name_acc = id_to_name_.access();
|
||||
auto result = id_to_name_acc.find(id);
|
||||
MG_ASSERT(result != id_to_name_acc.end(), "Trying to get a name for an invalid ID!");
|
||||
return result->name;
|
||||
void StoreMapping(std::unordered_map<uint64_t, std::string> id_to_name) {
|
||||
id_to_name_ = std::move(id_to_name);
|
||||
for (const auto &[id, name] : id_to_name_) {
|
||||
name_to_id_.emplace(name, id);
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t NameToId(std::string_view name) const {
|
||||
if (auto it = name_to_id_.find(name); it != name_to_id_.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return kUnmappedId;
|
||||
}
|
||||
|
||||
const std::string &IdToName(const uint64_t id) const {
|
||||
auto it = id_to_name_.find(id);
|
||||
MG_ASSERT(it != id_to_name_.end(), "Id not know in mapper!");
|
||||
return it->second;
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic<uint64_t> counter_{0};
|
||||
utils::SkipList<MapNameToId> name_to_id_;
|
||||
utils::SkipList<MapIdToName> id_to_name_;
|
||||
// Necessary for comparison with string_view nad string
|
||||
// https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0919r1.html
|
||||
// https://www.cppstories.com/2021/heterogeneous-access-cpp20/
|
||||
struct StringHash {
|
||||
using is_transparent = void;
|
||||
[[nodiscard]] size_t operator()(const char *txt) const { return std::hash<std::string_view>{}(txt); }
|
||||
[[nodiscard]] size_t operator()(std::string_view txt) const { return std::hash<std::string_view>{}(txt); }
|
||||
[[nodiscard]] size_t operator()(const std::string &txt) const { return std::hash<std::string>{}(txt); }
|
||||
};
|
||||
std::unordered_map<uint64_t, std::string> id_to_name_;
|
||||
std::unordered_map<std::string, uint64_t, StringHash, std::equal_to<>> name_to_id_;
|
||||
};
|
||||
} // namespace memgraph::storage::v3
|
||||
|
92
src/storage/v3/path.hpp
Normal file
92
src/storage/v3/path.hpp
Normal file
@ -0,0 +1,92 @@
|
||||
// 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 "storage/v3/edge_accessor.hpp"
|
||||
#include "storage/v3/vertex_accessor.hpp"
|
||||
#include "utils/logging.hpp"
|
||||
#include "utils/memory.hpp"
|
||||
|
||||
namespace memgraph::storage::v3 {
|
||||
|
||||
class Path {
|
||||
public:
|
||||
using allocator_type = utils::Allocator<char>;
|
||||
explicit Path(const VertexAccessor & /*vertex*/) {}
|
||||
|
||||
template <typename... TOthers>
|
||||
explicit Path(const VertexAccessor &vertex, const TOthers &...others) {}
|
||||
|
||||
template <typename... TOthers>
|
||||
Path(std::allocator_arg_t alloc, utils::MemoryResource *memory, const VertexAccessor &vertex,
|
||||
const TOthers &...others) {}
|
||||
|
||||
Path(const Path & /*other*/) {}
|
||||
|
||||
Path(const Path & /*other*/, utils::MemoryResource * /*memory*/) {}
|
||||
|
||||
// NOLINTNEXTLINE(readability-convert-member-functions-to-static)
|
||||
Path(Path &&other) noexcept : Path(std::move(other), other.GetMemoryResource()) {}
|
||||
|
||||
Path(Path && /*other*/, utils::MemoryResource * /*memory*/) {}
|
||||
|
||||
Path &operator=(const Path &) = default;
|
||||
|
||||
Path &operator=(Path &&) = default;
|
||||
|
||||
~Path() = default;
|
||||
|
||||
void Expand(const VertexAccessor &vertex) {}
|
||||
|
||||
void Expand(const EdgeAccessor &edge) {}
|
||||
|
||||
template <typename TFirst, typename... TOthers>
|
||||
void Expand(const TFirst &first, const TOthers &...others) {}
|
||||
|
||||
auto size() const;
|
||||
|
||||
std::pmr::vector<VertexAccessor> &vertices() {
|
||||
MG_ASSERT(false, "Using vertices on Path from storage!");
|
||||
return vertices_;
|
||||
}
|
||||
|
||||
std::pmr::vector<EdgeAccessor> &edges() {
|
||||
MG_ASSERT(false, "Using edges on Path from storage!");
|
||||
return edges_;
|
||||
}
|
||||
|
||||
const std::pmr::vector<VertexAccessor> &vertices() const {
|
||||
MG_ASSERT(false, "Using vertices on Path from storage!");
|
||||
return vertices_;
|
||||
}
|
||||
|
||||
const std::pmr::vector<EdgeAccessor> &edges() const {
|
||||
MG_ASSERT(false, "Using edges on Path from storage!");
|
||||
return edges_;
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(readability-convert-member-functions-to-static)
|
||||
utils::MemoryResource *GetMemoryResource() const {
|
||||
MG_ASSERT(false, "Using GetMemoryResource on Path from storage!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool operator==(const Path & /*other*/) const {
|
||||
MG_ASSERT(false, "Using operator= on Path from storage!");
|
||||
return false;
|
||||
};
|
||||
|
||||
private:
|
||||
std::pmr::vector<VertexAccessor> vertices_;
|
||||
std::pmr::vector<EdgeAccessor> edges_;
|
||||
};
|
||||
} // namespace memgraph::storage::v3
|
@ -820,6 +820,12 @@ Result<std::optional<EdgeAccessor>> Shard::Accessor::DeleteEdge(VertexId from_ve
|
||||
&transaction_, &shard_->indices_, &shard_->constraints_, config_, true);
|
||||
}
|
||||
|
||||
LabelId Shard::Accessor::NameToLabel(std::string_view name) const { return shard_->NameToLabel(name); }
|
||||
|
||||
PropertyId Shard::Accessor::NameToProperty(std::string_view name) const { return shard_->NameToProperty(name); }
|
||||
|
||||
EdgeTypeId Shard::Accessor::NameToEdgeType(std::string_view name) const { return shard_->NameToEdgeType(name); }
|
||||
|
||||
const std::string &Shard::Accessor::LabelToName(LabelId label) const { return shard_->LabelToName(label); }
|
||||
|
||||
const std::string &Shard::Accessor::PropertyToName(PropertyId property) const {
|
||||
@ -1096,6 +1102,16 @@ void Shard::Accessor::FinalizeTransaction() {
|
||||
}
|
||||
}
|
||||
|
||||
LabelId Shard::NameToLabel(std::string_view name) const { return LabelId::FromUint(name_id_mapper_.NameToId(name)); }
|
||||
|
||||
PropertyId Shard::NameToProperty(std::string_view name) const {
|
||||
return PropertyId::FromUint(name_id_mapper_.NameToId(name));
|
||||
}
|
||||
|
||||
EdgeTypeId Shard::NameToEdgeType(std::string_view name) const {
|
||||
return EdgeTypeId::FromUint(name_id_mapper_.NameToId(name));
|
||||
}
|
||||
|
||||
const std::string &Shard::LabelToName(LabelId label) const { return name_id_mapper_.IdToName(label.AsUint()); }
|
||||
|
||||
const std::string &Shard::PropertyToName(PropertyId property) const {
|
||||
@ -1734,6 +1750,10 @@ utils::BasicResult<Shard::CreateSnapshotError> Shard::CreateSnapshot() {
|
||||
return {};
|
||||
}
|
||||
|
||||
void Shard::StoreMapping(std::unordered_map<uint64_t, std::string> id_to_name) {
|
||||
name_id_mapper_.StoreMapping(std::move(id_to_name));
|
||||
}
|
||||
|
||||
bool Shard::LockPath() {
|
||||
auto locker_accessor = global_locker_.Access();
|
||||
return locker_accessor.AddPath(config_.durability.storage_directory);
|
||||
|
@ -316,8 +316,16 @@ class Shard final {
|
||||
/// @throw std::bad_alloc
|
||||
Result<std::optional<EdgeAccessor>> DeleteEdge(VertexId from_vertex_id, VertexId to_vertex_id, Gid edge_id);
|
||||
|
||||
LabelId NameToLabel(std::string_view name) const;
|
||||
|
||||
PropertyId NameToProperty(std::string_view name) const;
|
||||
|
||||
EdgeTypeId NameToEdgeType(std::string_view name) const;
|
||||
|
||||
const std::string &LabelToName(LabelId label) const;
|
||||
|
||||
const std::string &PropertyToName(PropertyId property) const;
|
||||
|
||||
const std::string &EdgeTypeToName(EdgeTypeId edge_type) const;
|
||||
|
||||
bool LabelIndexExists(LabelId label) const { return shard_->indices_.label_index.IndexExists(label); }
|
||||
@ -367,19 +375,18 @@ class Shard final {
|
||||
return Accessor{this, override_isolation_level.value_or(isolation_level_)};
|
||||
}
|
||||
|
||||
LabelId NameToLabel(std::string_view name) const;
|
||||
|
||||
PropertyId NameToProperty(std::string_view name) const;
|
||||
|
||||
EdgeTypeId NameToEdgeType(std::string_view name) const;
|
||||
|
||||
const std::string &LabelToName(LabelId label) const;
|
||||
|
||||
const std::string &PropertyToName(PropertyId property) const;
|
||||
|
||||
const std::string &EdgeTypeToName(EdgeTypeId edge_type) const;
|
||||
|
||||
/// @throw std::bad_alloc if unable to insert a new mapping
|
||||
LabelId NameToLabel(std::string_view name);
|
||||
|
||||
/// @throw std::bad_alloc if unable to insert a new mapping
|
||||
PropertyId NameToProperty(std::string_view name);
|
||||
|
||||
/// @throw std::bad_alloc if unable to insert a new mapping
|
||||
EdgeTypeId NameToEdgeType(std::string_view name);
|
||||
|
||||
/// @throw std::bad_alloc
|
||||
bool CreateIndex(LabelId label, std::optional<uint64_t> desired_commit_timestamp = {});
|
||||
|
||||
@ -485,6 +492,8 @@ class Shard final {
|
||||
|
||||
utils::BasicResult<CreateSnapshotError> CreateSnapshot();
|
||||
|
||||
void StoreMapping(std::unordered_map<uint64_t, std::string> id_to_name);
|
||||
|
||||
private:
|
||||
Transaction CreateTransaction(IsolationLevel isolation_level);
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "storage/v3/conversions.hpp"
|
||||
#include "storage/v3/edge_accessor.hpp"
|
||||
#include "storage/v3/id_types.hpp"
|
||||
#include "storage/v3/indices.hpp"
|
||||
@ -150,6 +151,8 @@ ResultSchema<bool> VertexAccessor::RemoveLabelAndValidate(LabelId label) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Result<bool> VertexAccessor::HasLabel(View view, LabelId label) const { return HasLabel(label, view); }
|
||||
|
||||
Result<bool> VertexAccessor::HasLabel(LabelId label, View view) const {
|
||||
bool exists = true;
|
||||
bool deleted = false;
|
||||
@ -371,6 +374,10 @@ Result<std::map<PropertyId, PropertyValue>> VertexAccessor::ClearProperties() {
|
||||
return std::move(properties);
|
||||
}
|
||||
|
||||
Result<PropertyValue> VertexAccessor::GetProperty(View view, PropertyId property) const {
|
||||
return GetProperty(property, view).GetValue();
|
||||
}
|
||||
|
||||
Result<PropertyValue> VertexAccessor::GetProperty(PropertyId property, View view) const {
|
||||
bool exists = true;
|
||||
bool deleted = false;
|
||||
|
@ -66,6 +66,8 @@ class VertexAccessor final {
|
||||
/// @throw std::bad_alloc
|
||||
ResultSchema<bool> RemoveLabelAndValidate(LabelId label);
|
||||
|
||||
Result<bool> HasLabel(View view, LabelId label) const;
|
||||
|
||||
Result<bool> HasLabel(LabelId label, View view) const;
|
||||
|
||||
/// @throw std::bad_alloc
|
||||
@ -90,6 +92,9 @@ class VertexAccessor final {
|
||||
/// @throw std::bad_alloc
|
||||
Result<PropertyValue> GetProperty(PropertyId property, View view) const;
|
||||
|
||||
// TODO Remove this
|
||||
Result<PropertyValue> GetProperty(View view, PropertyId property) const;
|
||||
|
||||
/// @throw std::bad_alloc
|
||||
Result<std::map<PropertyId, PropertyValue>> Properties(View view) const;
|
||||
|
||||
|
@ -325,6 +325,9 @@ target_link_libraries(storage_v3_test_utils mg-storage-v3)
|
||||
add_unit_test(storage_v3.cpp)
|
||||
target_link_libraries(${test_prefix}storage_v3 mg-storage-v3 storage_v3_test_utils)
|
||||
|
||||
add_unit_test(storage_v3_expr.cpp)
|
||||
target_link_libraries(${test_prefix}storage_v3_expr mg-storage-v3 mg-expr)
|
||||
|
||||
add_unit_test(storage_v3_schema.cpp)
|
||||
target_link_libraries(${test_prefix}storage_v3_schema mg-storage-v3)
|
||||
|
||||
|
@ -591,8 +591,10 @@ TEST_F(InterpreterTest, DummyTestToForceQueryV2Compilation) {
|
||||
// ASSERT_NO_THROW(Interpret("CREATE SCHEMA ON :A(a INTEGER);"));
|
||||
|
||||
// // Empty property list should result with syntax exception.
|
||||
// ASSERT_THROW(Interpret("CREATE CONSTRAINT ON (n:A) ASSERT IS UNIQUE;"), memgraph::query::v2::SyntaxException);
|
||||
// ASSERT_THROW(Interpret("DROP CONSTRAINT ON (n:A) ASSERT IS UNIQUE;"), memgraph::query::v2::SyntaxException);
|
||||
// ASSERT_THROW(Interpret("CREATE CONSTRAINT ON (n:A) ASSERT IS UNIQUE;"),
|
||||
// memgraph::frontend::opencypher::SyntaxException);
|
||||
// ASSERT_THROW(Interpret("DROP CONSTRAINT ON (n:A) ASSERT IS UNIQUE;"),
|
||||
// memgraph::frontend::opencypher::SyntaxException);
|
||||
|
||||
// // Too large list of properties should also result with syntax exception.
|
||||
// {
|
||||
@ -750,7 +752,8 @@ TEST_F(InterpreterTest, DummyTestToForceQueryV2Compilation) {
|
||||
// EXPECT_EQ(interpreter_context.plan_cache.size(), 0U);
|
||||
// EXPECT_EQ(interpreter_context.ast_cache.size(), 0U);
|
||||
// auto stream =
|
||||
// Interpret("EXPLAIN MATCH (n) WHERE n.id = $id RETURN *;", {{"id", memgraph::storage::v3::PropertyValue(42)}});
|
||||
// Interpret("EXPLAIN MATCH (n) WHERE n.id = $id RETURN *;", {{"id",
|
||||
// memgraph::storage::v3::PropertyValue(42)}});
|
||||
// ASSERT_EQ(stream.GetHeader().size(), 1U);
|
||||
// EXPECT_EQ(stream.GetHeader().front(), "QUERY PLAN");
|
||||
// std::vector<std::string> expected_rows{" * Produce {n}", " * Filter", " * ScanAll (n)", " * Once"};
|
||||
@ -765,9 +768,10 @@ TEST_F(InterpreterTest, DummyTestToForceQueryV2Compilation) {
|
||||
// EXPECT_EQ(interpreter_context.plan_cache.size(), 1U);
|
||||
// // We should have AST cache for EXPLAIN ... and for inner MATCH ...
|
||||
// EXPECT_EQ(interpreter_context.ast_cache.size(), 2U);
|
||||
// Interpret("MATCH (n) WHERE n.id = $id RETURN *;", {{"id", memgraph::storage::v3::PropertyValue("something
|
||||
// else")}}); EXPECT_EQ(interpreter_context.plan_cache.size(), 1U); EXPECT_EQ(interpreter_context.ast_cache.size(),
|
||||
// 2U);
|
||||
// Interpret("MATCH (n) WHERE n.id = $id RETURN *;", {{"id",
|
||||
// memgraph::storage::v3::PropertyValue("something else")}});
|
||||
// EXPECT_EQ(interpreter_context.plan_cache.size(), 1U);
|
||||
// EXPECT_EQ(interpreter_context.ast_cache.size(), 2U);
|
||||
// }
|
||||
|
||||
// TEST_F(InterpreterTest, ProfileQuery) {
|
||||
@ -776,12 +780,10 @@ TEST_F(InterpreterTest, DummyTestToForceQueryV2Compilation) {
|
||||
// EXPECT_EQ(interpreter_context.plan_cache.size(), 0U);
|
||||
// EXPECT_EQ(interpreter_context.ast_cache.size(), 0U);
|
||||
// auto stream = Interpret("PROFILE MATCH (n) RETURN *;");
|
||||
// std::vector<std::string> expected_header{"OPERATOR", "ACTUAL HITS", "RELATIVE TIME", "ABSOLUTE TIME"};
|
||||
// EXPECT_EQ(stream.GetHeader(), expected_header);
|
||||
// std::vector<std::string> expected_rows{"* Produce", "* ScanAll", "* Once"};
|
||||
// ASSERT_EQ(stream.GetResults().size(), expected_rows.size());
|
||||
// auto expected_it = expected_rows.begin();
|
||||
// for (const auto &row : stream.GetResults()) {
|
||||
// std::vector<std::string> expected_header{"OPERATOR", "ACTUAL HITS", "RELATIVE TIME", "ABSOLUTE
|
||||
// TIME"}; EXPECT_EQ(stream.GetHeader(), expected_header); std::vector<std::string> expected_rows{"*
|
||||
// Produce", "* ScanAll", "* Once"}; ASSERT_EQ(stream.GetResults().size(), expected_rows.size()); auto
|
||||
// expected_it = expected_rows.begin(); for (const auto &row : stream.GetResults()) {
|
||||
// ASSERT_EQ(row.size(), 4U);
|
||||
// EXPECT_EQ(row.front().ValueString(), *expected_it);
|
||||
// ++expected_it;
|
||||
@ -801,8 +803,8 @@ TEST_F(InterpreterTest, DummyTestToForceQueryV2Compilation) {
|
||||
// EXPECT_EQ(interpreter_context.plan_cache.size(), 0U);
|
||||
// EXPECT_EQ(interpreter_context.ast_cache.size(), 0U);
|
||||
// auto [stream, qid] = Prepare("PROFILE MATCH (n) RETURN *;");
|
||||
// std::vector<std::string> expected_header{"OPERATOR", "ACTUAL HITS", "RELATIVE TIME", "ABSOLUTE TIME"};
|
||||
// EXPECT_EQ(stream.GetHeader(), expected_header);
|
||||
// std::vector<std::string> expected_header{"OPERATOR", "ACTUAL HITS", "RELATIVE TIME", "ABSOLUTE
|
||||
// TIME"}; EXPECT_EQ(stream.GetHeader(), expected_header);
|
||||
|
||||
// std::vector<std::string> expected_rows{"* Produce", "* ScanAll", "* Once"};
|
||||
// auto expected_it = expected_rows.begin();
|
||||
@ -835,8 +837,8 @@ TEST_F(InterpreterTest, DummyTestToForceQueryV2Compilation) {
|
||||
|
||||
// TEST_F(InterpreterTest, ProfileQueryInMulticommandTransaction) {
|
||||
// Interpret("BEGIN");
|
||||
// ASSERT_THROW(Interpret("PROFILE MATCH (n) RETURN *;"), memgraph::query::v2::ProfileInMulticommandTxException);
|
||||
// Interpret("ROLLBACK");
|
||||
// ASSERT_THROW(Interpret("PROFILE MATCH (n) RETURN *;"),
|
||||
// memgraph::query::v2::ProfileInMulticommandTxException); Interpret("ROLLBACK");
|
||||
// }
|
||||
|
||||
// TEST_F(InterpreterTest, ProfileQueryWithParams) {
|
||||
@ -845,13 +847,13 @@ TEST_F(InterpreterTest, DummyTestToForceQueryV2Compilation) {
|
||||
// EXPECT_EQ(interpreter_context.plan_cache.size(), 0U);
|
||||
// EXPECT_EQ(interpreter_context.ast_cache.size(), 0U);
|
||||
// auto stream =
|
||||
// Interpret("PROFILE MATCH (n) WHERE n.id = $id RETURN *;", {{"id", memgraph::storage::v3::PropertyValue(42)}});
|
||||
// std::vector<std::string> expected_header{"OPERATOR", "ACTUAL HITS", "RELATIVE TIME", "ABSOLUTE TIME"};
|
||||
// EXPECT_EQ(stream.GetHeader(), expected_header);
|
||||
// std::vector<std::string> expected_rows{"* Produce", "* Filter", "* ScanAll", "* Once"};
|
||||
// ASSERT_EQ(stream.GetResults().size(), expected_rows.size());
|
||||
// auto expected_it = expected_rows.begin();
|
||||
// for (const auto &row : stream.GetResults()) {
|
||||
// Interpret("PROFILE MATCH (n) WHERE n.id = $id RETURN *;", {{"id",
|
||||
// memgraph::storage::v3::PropertyValue(42)}});
|
||||
// std::vector<std::string> expected_header{"OPERATOR", "ACTUAL HITS", "RELATIVE TIME", "ABSOLUTE
|
||||
// TIME"}; EXPECT_EQ(stream.GetHeader(), expected_header); std::vector<std::string> expected_rows{"*
|
||||
// Produce", "* Filter", "* ScanAll", "* Once"}; ASSERT_EQ(stream.GetResults().size(),
|
||||
// expected_rows.size()); auto expected_it = expected_rows.begin(); for (const auto &row :
|
||||
// stream.GetResults()) {
|
||||
// ASSERT_EQ(row.size(), 4U);
|
||||
// EXPECT_EQ(row.front().ValueString(), *expected_it);
|
||||
// ++expected_it;
|
||||
@ -860,9 +862,10 @@ TEST_F(InterpreterTest, DummyTestToForceQueryV2Compilation) {
|
||||
// EXPECT_EQ(interpreter_context.plan_cache.size(), 1U);
|
||||
// // We should have AST cache for PROFILE ... and for inner MATCH ...
|
||||
// EXPECT_EQ(interpreter_context.ast_cache.size(), 2U);
|
||||
// Interpret("MATCH (n) WHERE n.id = $id RETURN *;", {{"id", memgraph::storage::v3::PropertyValue("something
|
||||
// else")}}); EXPECT_EQ(interpreter_context.plan_cache.size(), 1U); EXPECT_EQ(interpreter_context.ast_cache.size(),
|
||||
// 2U);
|
||||
// Interpret("MATCH (n) WHERE n.id = $id RETURN *;", {{"id",
|
||||
// memgraph::storage::v3::PropertyValue("something else")}});
|
||||
// EXPECT_EQ(interpreter_context.plan_cache.size(), 1U);
|
||||
// EXPECT_EQ(interpreter_context.ast_cache.size(), 2U);
|
||||
// }
|
||||
|
||||
// TEST_F(InterpreterTest, ProfileQueryWithLiterals) {
|
||||
@ -872,10 +875,9 @@ TEST_F(InterpreterTest, DummyTestToForceQueryV2Compilation) {
|
||||
// EXPECT_EQ(interpreter_context.plan_cache.size(), 0U);
|
||||
// EXPECT_EQ(interpreter_context.ast_cache.size(), 1U);
|
||||
// auto stream = Interpret("PROFILE UNWIND range(1, 1000) AS x CREATE (:Node {id: x});", {});
|
||||
// std::vector<std::string> expected_header{"OPERATOR", "ACTUAL HITS", "RELATIVE TIME", "ABSOLUTE TIME"};
|
||||
// EXPECT_EQ(stream.GetHeader(), expected_header);
|
||||
// std::vector<std::string> expected_rows{"* CreateNode", "* Unwind", "* Once"};
|
||||
// ASSERT_EQ(stream.GetResults().size(), expected_rows.size());
|
||||
// std::vector<std::string> expected_header{"OPERATOR", "ACTUAL HITS", "RELATIVE TIME", "ABSOLUTE
|
||||
// TIME"}; EXPECT_EQ(stream.GetHeader(), expected_header); std::vector<std::string> expected_rows{"*
|
||||
// CreateNode", "* Unwind", "* Once"}; ASSERT_EQ(stream.GetResults().size(), expected_rows.size());
|
||||
// auto expected_it = expected_rows.begin();
|
||||
// for (const auto &row : stream.GetResults()) {
|
||||
// ASSERT_EQ(row.size(), 4U);
|
||||
@ -894,11 +896,12 @@ TEST_F(InterpreterTest, DummyTestToForceQueryV2Compilation) {
|
||||
// TEST_F(InterpreterTest, Transactions) {
|
||||
// auto &interpreter = default_interpreter.interpreter;
|
||||
// {
|
||||
// ASSERT_THROW(interpreter.CommitTransaction(), memgraph::query::v2::ExplicitTransactionUsageException);
|
||||
// ASSERT_THROW(interpreter.RollbackTransaction(), memgraph::query::v2::ExplicitTransactionUsageException);
|
||||
// interpreter.BeginTransaction();
|
||||
// ASSERT_THROW(interpreter.BeginTransaction(), memgraph::query::v2::ExplicitTransactionUsageException);
|
||||
// auto [stream, qid] = Prepare("RETURN 2");
|
||||
// ASSERT_THROW(interpreter.CommitTransaction(),
|
||||
// memgraph::query::v2::ExplicitTransactionUsageException);
|
||||
// ASSERT_THROW(interpreter.RollbackTransaction(),
|
||||
// memgraph::query::v2::ExplicitTransactionUsageException); interpreter.BeginTransaction();
|
||||
// ASSERT_THROW(interpreter.BeginTransaction(),
|
||||
// memgraph::query::v2::ExplicitTransactionUsageException); auto [stream, qid] = Prepare("RETURN 2");
|
||||
// ASSERT_EQ(stream.GetHeader().size(), 1U);
|
||||
// EXPECT_EQ(stream.GetHeader()[0], "2");
|
||||
// Pull(&stream, 1);
|
||||
@ -1072,8 +1075,8 @@ TEST_F(InterpreterTest, DummyTestToForceQueryV2Compilation) {
|
||||
// writer.Close();
|
||||
|
||||
// {
|
||||
// const std::string query = fmt::format(R"(LOAD CSV FROM "{}" WITH HEADER IGNORE BAD DELIMITER "{}" AS x RETURN
|
||||
// x.A)",
|
||||
// const std::string query = fmt::format(R"(LOAD CSV FROM "{}" WITH HEADER IGNORE BAD DELIMITER "{}"
|
||||
// AS x RETURN x.A)",
|
||||
// csv_path.string(), delimiter);
|
||||
// auto [stream, qid] = Prepare(query);
|
||||
// ASSERT_EQ(stream.GetHeader().size(), 1U);
|
||||
@ -1093,8 +1096,8 @@ TEST_F(InterpreterTest, DummyTestToForceQueryV2Compilation) {
|
||||
// }
|
||||
|
||||
// {
|
||||
// const std::string query = fmt::format(R"(LOAD CSV FROM "{}" WITH HEADER IGNORE BAD DELIMITER "{}" AS x RETURN
|
||||
// x.C)",
|
||||
// const std::string query = fmt::format(R"(LOAD CSV FROM "{}" WITH HEADER IGNORE BAD DELIMITER "{}"
|
||||
// AS x RETURN x.C)",
|
||||
// csv_path.string(), delimiter);
|
||||
// auto [stream, qid] = Prepare(query);
|
||||
// ASSERT_EQ(stream.GetHeader().size(), 1U);
|
||||
@ -1140,8 +1143,8 @@ TEST_F(InterpreterTest, DummyTestToForceQueryV2Compilation) {
|
||||
|
||||
// const std::array<std::string, 2> queries = {
|
||||
// fmt::format("LOAD CSV FROM \"{}\" WITH HEADER AS row RETURN row", csv_path.string()),
|
||||
// "CREATE TRIGGER trigger ON CREATE BEFORE COMMIT EXECUTE LOAD CSV FROM 'file.csv' WITH HEADER AS row RETURN "
|
||||
// "row"};
|
||||
// "CREATE TRIGGER trigger ON CREATE BEFORE COMMIT EXECUTE LOAD CSV FROM 'file.csv' WITH HEADER
|
||||
// AS row RETURN " "row"};
|
||||
|
||||
// InterpreterFaker interpreter_faker{&db_, {.query = {.allow_load_csv = allow_load_csv}},
|
||||
// directory_manager.Path()}; for (const auto &query : queries) {
|
||||
@ -1164,8 +1167,9 @@ TEST_F(InterpreterTest, DummyTestToForceQueryV2Compilation) {
|
||||
// void AssertAllValuesAreZero(const std::map<std::string, memgraph::communication::bolt::Value> &map,
|
||||
// const std::vector<std::string> &exceptions) {
|
||||
// for (const auto &[key, value] : map) {
|
||||
// if (const auto it = std::find(exceptions.begin(), exceptions.end(), key); it != exceptions.end()) continue;
|
||||
// ASSERT_EQ(value.ValueInt(), 0) << "Value " << key << " actual: " << value.ValueInt() << ", expected 0";
|
||||
// if (const auto it = std::find(exceptions.begin(), exceptions.end(), key); it != exceptions.end())
|
||||
// continue; ASSERT_EQ(value.ValueInt(), 0) << "Value " << key << " actual: " << value.ValueInt() <<
|
||||
// ", expected 0";
|
||||
// }
|
||||
// }
|
||||
|
||||
@ -1178,7 +1182,8 @@ TEST_F(InterpreterTest, DummyTestToForceQueryV2Compilation) {
|
||||
// }
|
||||
// {
|
||||
// EXPECT_NO_THROW(Interpret("CREATE SCHEMA ON :L1(name STRING)"));
|
||||
// std::array stats_keys{"nodes-created", "nodes-deleted", "relationships-created", "relationships-deleted",
|
||||
// std::array stats_keys{"nodes-created", "nodes-deleted", "relationships-created",
|
||||
// "relationships-deleted",
|
||||
// "properties-set", "labels-added", "labels-removed"};
|
||||
// auto [stream, qid] = Prepare("CREATE (:L1 {name: 'name1'});");
|
||||
// Pull(&stream);
|
||||
@ -1187,7 +1192,8 @@ TEST_F(InterpreterTest, DummyTestToForceQueryV2Compilation) {
|
||||
// ASSERT_TRUE(stream.GetSummary().at("stats").IsMap());
|
||||
// auto stats = stream.GetSummary().at("stats").ValueMap();
|
||||
// ASSERT_TRUE(
|
||||
// std::all_of(stats_keys.begin(), stats_keys.end(), [&stats](const auto &key) { return stats.contains(key);
|
||||
// std::all_of(stats_keys.begin(), stats_keys.end(), [&stats](const auto &key) { return
|
||||
// stats.contains(key);
|
||||
// }));
|
||||
// AssertAllValuesAreZero(stats, {"nodes-created"});
|
||||
// }
|
||||
@ -1197,7 +1203,8 @@ TEST_F(InterpreterTest, DummyTestToForceQueryV2Compilation) {
|
||||
// EXPECT_NO_THROW(Interpret("CREATE SCHEMA ON :L1(name STRING)"));
|
||||
// {
|
||||
// auto [stream, qid] =
|
||||
// Prepare("CREATE (:L1{name: 'name1'}),(:L1{name: 'name2'}),(:L1{name: 'name3'}),(:L1{name: 'name4'});");
|
||||
// Prepare("CREATE (:L1{name: 'name1'}),(:L1{name: 'name2'}),(:L1{name: 'name3'}),(:L1{name:
|
||||
// 'name4'});");
|
||||
|
||||
// Pull(&stream);
|
||||
// auto stats = stream.GetSummary().at("stats").ValueMap();
|
||||
@ -1214,7 +1221,8 @@ TEST_F(InterpreterTest, DummyTestToForceQueryV2Compilation) {
|
||||
// }
|
||||
// {
|
||||
// auto [stream, qid] =
|
||||
// Prepare("CREATE (n:L1 {name: 'name5'})-[:TO]->(m:L1{name: 'name6'}), (n)-[:TO]->(m), (n)-[:TO]->(m);");
|
||||
// Prepare("CREATE (n:L1 {name: 'name5'})-[:TO]->(m:L1{name: 'name6'}), (n)-[:TO]->(m),
|
||||
// (n)-[:TO]->(m);");
|
||||
|
||||
// Pull(&stream);
|
||||
|
||||
@ -1319,8 +1327,8 @@ TEST_F(InterpreterTest, DummyTestToForceQueryV2Compilation) {
|
||||
// auto notification = notifications[0].ValueMap();
|
||||
// ASSERT_EQ(notification["severity"].ValueString(), "INFO");
|
||||
// ASSERT_EQ(notification["code"].ValueString(), "IndexAlreadyExists");
|
||||
// ASSERT_EQ(notification["title"].ValueString(), "Index on label Person on properties id already exists.");
|
||||
// ASSERT_EQ(notification["description"].ValueString(), "");
|
||||
// ASSERT_EQ(notification["title"].ValueString(), "Index on label Person on properties id already
|
||||
// exists."); ASSERT_EQ(notification["description"].ValueString(), "");
|
||||
// }
|
||||
// {
|
||||
// auto [stream, qid] = Prepare("DROP INDEX ON :Person(id);");
|
||||
@ -1345,8 +1353,8 @@ TEST_F(InterpreterTest, DummyTestToForceQueryV2Compilation) {
|
||||
// auto notification = notifications[0].ValueMap();
|
||||
// ASSERT_EQ(notification["severity"].ValueString(), "INFO");
|
||||
// ASSERT_EQ(notification["code"].ValueString(), "IndexDoesNotExist");
|
||||
// ASSERT_EQ(notification["title"].ValueString(), "Index on label Person on properties id doesn't exist.");
|
||||
// ASSERT_EQ(notification["description"].ValueString(), "");
|
||||
// ASSERT_EQ(notification["title"].ValueString(), "Index on label Person on properties id doesn't
|
||||
// exist."); ASSERT_EQ(notification["description"].ValueString(), "");
|
||||
// }
|
||||
// }
|
||||
|
||||
@ -1420,8 +1428,8 @@ TEST_F(InterpreterTest, DummyTestToForceQueryV2Compilation) {
|
||||
// auto notification = notifications[0].ValueMap();
|
||||
// ASSERT_EQ(notification["severity"].ValueString(), "INFO");
|
||||
// ASSERT_EQ(notification["code"].ValueString(), "CreateConstraint");
|
||||
// ASSERT_EQ(notification["title"].ValueString(), "Created EXISTS constraint on label L1 on properties name.");
|
||||
// ASSERT_EQ(notification["description"].ValueString(), "");
|
||||
// ASSERT_EQ(notification["title"].ValueString(), "Created EXISTS constraint on label L1 on
|
||||
// properties name."); ASSERT_EQ(notification["description"].ValueString(), "");
|
||||
// }
|
||||
// {
|
||||
// auto [stream, qid] = Prepare("CREATE CONSTRAINT ON (n:L1) ASSERT EXISTS (n.name);");
|
||||
@ -1433,8 +1441,8 @@ TEST_F(InterpreterTest, DummyTestToForceQueryV2Compilation) {
|
||||
// auto notification = notifications[0].ValueMap();
|
||||
// ASSERT_EQ(notification["severity"].ValueString(), "INFO");
|
||||
// ASSERT_EQ(notification["code"].ValueString(), "ConstraintAlreadyExists");
|
||||
// ASSERT_EQ(notification["title"].ValueString(), "Constraint EXISTS on label L1 on properties name already
|
||||
// exists."); ASSERT_EQ(notification["description"].ValueString(), "");
|
||||
// ASSERT_EQ(notification["title"].ValueString(), "Constraint EXISTS on label L1 on properties name
|
||||
// already exists."); ASSERT_EQ(notification["description"].ValueString(), "");
|
||||
// }
|
||||
// {
|
||||
// auto [stream, qid] = Prepare("DROP CONSTRAINT ON (n:L1) ASSERT EXISTS (n.name);");
|
||||
@ -1446,8 +1454,8 @@ TEST_F(InterpreterTest, DummyTestToForceQueryV2Compilation) {
|
||||
// auto notification = notifications[0].ValueMap();
|
||||
// ASSERT_EQ(notification["severity"].ValueString(), "INFO");
|
||||
// ASSERT_EQ(notification["code"].ValueString(), "DropConstraint");
|
||||
// ASSERT_EQ(notification["title"].ValueString(), "Dropped EXISTS constraint on label L1 on properties name.");
|
||||
// ASSERT_EQ(notification["description"].ValueString(), "");
|
||||
// ASSERT_EQ(notification["title"].ValueString(), "Dropped EXISTS constraint on label L1 on
|
||||
// properties name."); ASSERT_EQ(notification["description"].ValueString(), "");
|
||||
// }
|
||||
// {
|
||||
// auto [stream, qid] = Prepare("DROP CONSTRAINT ON (n:L1) ASSERT EXISTS (n.name);");
|
||||
@ -1459,8 +1467,8 @@ TEST_F(InterpreterTest, DummyTestToForceQueryV2Compilation) {
|
||||
// auto notification = notifications[0].ValueMap();
|
||||
// ASSERT_EQ(notification["severity"].ValueString(), "INFO");
|
||||
// ASSERT_EQ(notification["code"].ValueString(), "ConstraintDoesNotExist");
|
||||
// ASSERT_EQ(notification["title"].ValueString(), "Constraint EXISTS on label L1 on properties name doesn'texist.");
|
||||
// ASSERT_EQ(notification["description"].ValueString(), "");
|
||||
// ASSERT_EQ(notification["title"].ValueString(), "Constraint EXISTS on label L1 on properties name
|
||||
// doesn'texist."); ASSERT_EQ(notification["description"].ValueString(), "");
|
||||
// }
|
||||
// }
|
||||
|
||||
@ -1510,7 +1518,8 @@ TEST_F(InterpreterTest, DummyTestToForceQueryV2Compilation) {
|
||||
|
||||
// writer.Close();
|
||||
|
||||
// const std::string query = fmt::format(R"(LOAD CSV FROM "{}" WITH HEADER IGNORE BAD DELIMITER "{}" AS x RETURN x;)",
|
||||
// const std::string query = fmt::format(R"(LOAD CSV FROM "{}" WITH HEADER IGNORE BAD DELIMITER "{}" AS
|
||||
// x RETURN x;)",
|
||||
// csv_path.string(), delimiter);
|
||||
// auto [stream, qid] = Prepare(query);
|
||||
// Pull(&stream);
|
||||
@ -1522,9 +1531,9 @@ TEST_F(InterpreterTest, DummyTestToForceQueryV2Compilation) {
|
||||
// ASSERT_EQ(notification["severity"].ValueString(), "INFO");
|
||||
// ASSERT_EQ(notification["code"].ValueString(), "LoadCSVTip");
|
||||
// ASSERT_EQ(notification["title"].ValueString(),
|
||||
// "It's important to note that the parser parses the values as strings. It's up to the user to "
|
||||
// "convert the parsed row values to the appropriate type. This can be done using the built-in "
|
||||
// "conversion functions such as ToInteger, ToFloat, ToBoolean etc.");
|
||||
// "It's important to note that the parser parses the values as strings. It's up to the user
|
||||
// to " "convert the parsed row values to the appropriate type. This can be done using the
|
||||
// built-in " "conversion functions such as ToInteger, ToFloat, ToBoolean etc.");
|
||||
// ASSERT_EQ(notification["description"].ValueString(), "");
|
||||
// }
|
||||
|
||||
@ -1543,30 +1552,32 @@ TEST_F(InterpreterTest, DummyTestToForceQueryV2Compilation) {
|
||||
|
||||
// TEST_F(InterpreterTest, ShowSchemaMulticommandTransaction) {
|
||||
// Interpret("BEGIN");
|
||||
// ASSERT_THROW(Interpret("SHOW SCHEMA ON :label"), memgraph::query::v2::ConstraintInMulticommandTxException);
|
||||
// Interpret("ROLLBACK");
|
||||
// ASSERT_THROW(Interpret("SHOW SCHEMA ON :label"),
|
||||
// memgraph::query::v2::ConstraintInMulticommandTxException); Interpret("ROLLBACK");
|
||||
// }
|
||||
|
||||
// TEST_F(InterpreterTest, DropSchemaMulticommandTransaction) {
|
||||
// Interpret("BEGIN");
|
||||
// ASSERT_THROW(Interpret("DROP SCHEMA ON :label"), memgraph::query::v2::ConstraintInMulticommandTxException);
|
||||
// Interpret("ROLLBACK");
|
||||
// ASSERT_THROW(Interpret("DROP SCHEMA ON :label"),
|
||||
// memgraph::query::v2::ConstraintInMulticommandTxException); Interpret("ROLLBACK");
|
||||
// }
|
||||
|
||||
// TEST_F(InterpreterTest, SchemaTestCreateAndShow) {
|
||||
// // Empty schema type map should result with syntax exception.
|
||||
// ASSERT_THROW(Interpret("CREATE SCHEMA ON :label();"), memgraph::query::v2::SyntaxException);
|
||||
// ASSERT_THROW(Interpret("CREATE SCHEMA ON :label();"),
|
||||
// memgraph::frontend::opencypher::SyntaxException);
|
||||
|
||||
// // Duplicate properties are should also cause an exception
|
||||
// ASSERT_THROW(Interpret("CREATE SCHEMA ON :label(name STRING, name STRING);"),
|
||||
// memgraph::query::v2::SemanticException); ASSERT_THROW(Interpret("CREATE SCHEMA ON :label(name STRING, name
|
||||
// INTEGER);"),
|
||||
// memgraph::query::v2::SemanticException); ASSERT_THROW(Interpret("CREATE SCHEMA ON :label(name
|
||||
// STRING, name INTEGER);"),
|
||||
// memgraph::query::v2::SemanticException);
|
||||
|
||||
// {
|
||||
// // Cannot create same schema twice
|
||||
// Interpret("CREATE SCHEMA ON :label(name STRING, age INTEGER)");
|
||||
// ASSERT_THROW(Interpret("CREATE SCHEMA ON :label(name STRING);"), memgraph::query::v2::QueryException);
|
||||
// ASSERT_THROW(Interpret("CREATE SCHEMA ON :label(name STRING);"),
|
||||
// memgraph::query::v2::QueryException);
|
||||
// }
|
||||
// // Show schema
|
||||
// {
|
||||
@ -1610,7 +1621,8 @@ TEST_F(InterpreterTest, DummyTestToForceQueryV2Compilation) {
|
||||
// ASSERT_TRUE(result_table.contains(key1));
|
||||
// const auto primary_key_split = StringToUnorderedSet(result[1].ValueString());
|
||||
// ASSERT_EQ(primary_key_split.size(), 2);
|
||||
// ASSERT_TRUE(primary_key_split == result_table[key1]) << "actual value is: " << result[1].ValueString();
|
||||
// ASSERT_TRUE(primary_key_split == result_table[key1]) << "actual value is: " <<
|
||||
// result[1].ValueString();
|
||||
|
||||
// const auto &result2 = stream.GetResults().front();
|
||||
// ASSERT_EQ(result2.size(), 2U);
|
||||
@ -1618,14 +1630,16 @@ TEST_F(InterpreterTest, DummyTestToForceQueryV2Compilation) {
|
||||
// ASSERT_TRUE(result_table.contains(key2));
|
||||
// const auto primary_key_split2 = StringToUnorderedSet(result2[1].ValueString());
|
||||
// ASSERT_EQ(primary_key_split2.size(), 2);
|
||||
// ASSERT_TRUE(primary_key_split2 == result_table[key2]) << "Real value is: " << result[1].ValueString();
|
||||
// ASSERT_TRUE(primary_key_split2 == result_table[key2]) << "Real value is: " <<
|
||||
// result[1].ValueString();
|
||||
// }
|
||||
// }
|
||||
|
||||
// TEST_F(InterpreterTest, SchemaTestCreateDropAndShow) {
|
||||
// Interpret("CREATE SCHEMA ON :label(name STRING, age INTEGER)");
|
||||
// // Wrong syntax for dropping schema.
|
||||
// ASSERT_THROW(Interpret("DROP SCHEMA ON :label();"), memgraph::query::v2::SyntaxException);
|
||||
// ASSERT_THROW(Interpret("DROP SCHEMA ON :label();"),
|
||||
// memgraph::frontend::opencypher::SyntaxException);
|
||||
// // Cannot drop non existant schema.
|
||||
// ASSERT_THROW(Interpret("DROP SCHEMA ON :label1;"), memgraph::query::v2::QueryException);
|
||||
|
||||
|
@ -35,6 +35,7 @@ namespace memgraph::storage::v3::tests {
|
||||
class StorageV3 : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
store.StoreMapping({{1, "label"}, {2, "property"}});
|
||||
ASSERT_TRUE(
|
||||
store.CreateSchema(primary_label, {storage::v3::SchemaProperty{primary_property, common::SchemaType::INT}}));
|
||||
}
|
||||
@ -47,21 +48,16 @@ class StorageV3 : public ::testing::Test {
|
||||
return *vtx;
|
||||
}
|
||||
|
||||
LabelId NameToLabelId(std::string_view label_name) { return LabelId::FromUint(id_mapper.NameToId(label_name)); }
|
||||
LabelId NameToLabelId(std::string_view label_name) { return store.NameToLabel(label_name); }
|
||||
|
||||
PropertyId NameToPropertyId(std::string_view property_name) {
|
||||
return PropertyId::FromUint(id_mapper.NameToId(property_name));
|
||||
}
|
||||
PropertyId NameToPropertyId(std::string_view property_name) { return store.NameToProperty(property_name); }
|
||||
|
||||
EdgeTypeId NameToEdgeTypeId(std::string_view edge_type_name) {
|
||||
return EdgeTypeId::FromUint(id_mapper.NameToId(edge_type_name));
|
||||
}
|
||||
EdgeTypeId NameToEdgeTypeId(std::string_view edge_type_name) { return store.NameToEdgeType(edge_type_name); }
|
||||
|
||||
NameIdMapper id_mapper;
|
||||
const std::vector<PropertyValue> pk{PropertyValue{0}};
|
||||
const LabelId primary_label{NameToLabelId("label")};
|
||||
const LabelId primary_label{LabelId::FromUint(1)};
|
||||
Shard store{primary_label, pk, std::nullopt};
|
||||
const PropertyId primary_property{NameToPropertyId("property")};
|
||||
const PropertyId primary_property{PropertyId::FromUint(2)};
|
||||
};
|
||||
|
||||
// NOLINTNEXTLINE(hicpp-special-member-functions)
|
||||
@ -875,6 +871,7 @@ TEST_F(StorageV3, VertexDeleteProperty) {
|
||||
|
||||
// NOLINTNEXTLINE(hicpp-special-member-functions)
|
||||
TEST_F(StorageV3, VertexLabelCommit) {
|
||||
store.StoreMapping({{1, "label"}, {2, "property"}, {3, "label5"}, {4, "other"}});
|
||||
{
|
||||
auto acc = store.Access();
|
||||
auto vertex = CreateVertexAndValidate(acc, primary_label, {}, {{primary_property, PropertyValue{0}}});
|
||||
@ -987,6 +984,7 @@ TEST_F(StorageV3, VertexLabelCommit) {
|
||||
|
||||
// NOLINTNEXTLINE(hicpp-special-member-functions)
|
||||
TEST_F(StorageV3, VertexLabelAbort) {
|
||||
store.StoreMapping({{1, "label"}, {2, "property"}, {3, "label5"}, {4, "other"}});
|
||||
// Create the vertex.
|
||||
{
|
||||
auto acc = store.Access();
|
||||
@ -1231,6 +1229,7 @@ TEST_F(StorageV3, VertexLabelAbort) {
|
||||
|
||||
// NOLINTNEXTLINE(hicpp-special-member-functions)
|
||||
TEST_F(StorageV3, VertexLabelSerializationError) {
|
||||
store.StoreMapping({{1, "label"}, {2, "property"}, {3, "label1"}, {4, "label2"}});
|
||||
{
|
||||
auto acc = store.Access();
|
||||
CreateVertexAndValidate(acc, primary_label, {}, {{primary_property, PropertyValue{0}}});
|
||||
@ -1335,6 +1334,7 @@ TEST_F(StorageV3, VertexLabelSerializationError) {
|
||||
|
||||
// NOLINTNEXTLINE(hicpp-special-member-functions)
|
||||
TEST_F(StorageV3, VertexPropertyCommit) {
|
||||
store.StoreMapping({{1, "label"}, {2, "property"}, {3, "property5"}, {4, "other"}});
|
||||
{
|
||||
auto acc = store.Access();
|
||||
auto vertex = CreateVertexAndValidate(acc, primary_label, {}, {{primary_property, PropertyValue{0}}});
|
||||
@ -1454,6 +1454,7 @@ TEST_F(StorageV3, VertexPropertyCommit) {
|
||||
|
||||
// NOLINTNEXTLINE(hicpp-special-member-functions)
|
||||
TEST_F(StorageV3, VertexPropertyAbort) {
|
||||
store.StoreMapping({{1, "label"}, {2, "property"}, {3, "property5"}, {4, "other"}});
|
||||
// Create the vertex.
|
||||
{
|
||||
auto acc = store.Access();
|
||||
@ -1728,6 +1729,7 @@ TEST_F(StorageV3, VertexPropertyAbort) {
|
||||
|
||||
// NOLINTNEXTLINE(hicpp-special-member-functions)
|
||||
TEST_F(StorageV3, VertexPropertySerializationError) {
|
||||
store.StoreMapping({{1, "label"}, {2, "property"}, {3, "property1"}, {4, "property2"}});
|
||||
{
|
||||
auto acc = store.Access();
|
||||
CreateVertexAndValidate(acc, primary_label, {}, {{primary_property, PropertyValue{0}}});
|
||||
@ -1826,6 +1828,7 @@ TEST_F(StorageV3, VertexPropertySerializationError) {
|
||||
|
||||
// NOLINTNEXTLINE(hicpp-special-member-functions)
|
||||
TEST_F(StorageV3, VertexLabelPropertyMixed) {
|
||||
store.StoreMapping({{1, "label"}, {2, "property"}, {3, "label5"}, {4, "property5"}});
|
||||
auto acc = store.Access();
|
||||
auto vertex = CreateVertexAndValidate(acc, primary_label, {}, {{primary_property, PropertyValue{0}}});
|
||||
|
||||
@ -2064,6 +2067,7 @@ TEST_F(StorageV3, VertexLabelPropertyMixed) {
|
||||
}
|
||||
|
||||
TEST_F(StorageV3, VertexPropertyClear) {
|
||||
store.StoreMapping({{1, "label"}, {2, "property"}, {3, "property1"}, {4, "property2"}});
|
||||
auto property1 = NameToPropertyId("property1");
|
||||
auto property2 = NameToPropertyId("property2");
|
||||
{
|
||||
@ -2166,6 +2170,8 @@ TEST_F(StorageV3, VertexPropertyClear) {
|
||||
}
|
||||
|
||||
TEST_F(StorageV3, VertexNonexistentLabelPropertyEdgeAPI) {
|
||||
store.StoreMapping({{1, "label"}, {2, "property"}, {3, "label1"}, {4, "property1"}, {5, "edge"}});
|
||||
|
||||
auto label1 = NameToLabelId("label1");
|
||||
auto property1 = NameToPropertyId("property1");
|
||||
|
||||
|
@ -25,35 +25,33 @@ using testing::UnorderedElementsAre;
|
||||
class StorageEdgeTest : public ::testing::TestWithParam<bool> {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
store.StoreMapping({{1, "label"}, {2, "property"}, {3, "et5"}, {4, "other"}, {5, "different_label"}});
|
||||
ASSERT_TRUE(
|
||||
store.CreateSchema(primary_label, {storage::v3::SchemaProperty{primary_property, common::SchemaType::INT}}));
|
||||
}
|
||||
|
||||
[[nodiscard]] LabelId NameToLabelId(std::string_view label_name) {
|
||||
return LabelId::FromUint(id_mapper.NameToId(label_name));
|
||||
}
|
||||
[[nodiscard]] LabelId NameToLabelId(std::string_view label_name) { return store.NameToLabel(label_name); }
|
||||
|
||||
[[nodiscard]] PropertyId NameToPropertyId(std::string_view property_name) {
|
||||
return PropertyId::FromUint(id_mapper.NameToId(property_name));
|
||||
return store.NameToProperty(property_name);
|
||||
}
|
||||
|
||||
[[nodiscard]] EdgeTypeId NameToEdgeTypeId(std::string_view edge_type_name) {
|
||||
return EdgeTypeId::FromUint(id_mapper.NameToId(edge_type_name));
|
||||
return store.NameToEdgeType(edge_type_name);
|
||||
}
|
||||
|
||||
ResultSchema<VertexAccessor> CreateVertex(Shard::Accessor &acc, const PropertyValue &key) {
|
||||
return acc.CreateVertexAndValidate(primary_label, {}, {{primary_property, key}});
|
||||
}
|
||||
|
||||
NameIdMapper id_mapper;
|
||||
static constexpr int64_t min_primary_key_value{0};
|
||||
static constexpr int64_t max_primary_key_value{10000};
|
||||
const LabelId primary_label{NameToLabelId("label")};
|
||||
const LabelId primary_label{LabelId::FromUint(1)};
|
||||
Shard store{primary_label,
|
||||
{PropertyValue{min_primary_key_value}},
|
||||
std::vector{PropertyValue{max_primary_key_value}},
|
||||
Config{.items = {.properties_on_edges = GetParam()}}};
|
||||
const PropertyId primary_property{NameToPropertyId("property")};
|
||||
const PropertyId primary_property{PropertyId::FromUint(2)};
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(EdgesWithProperties, StorageEdgeTest, ::testing::Values(true));
|
||||
|
2190
tests/unit/storage_v3_expr.cpp
Normal file
2190
tests/unit/storage_v3_expr.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@ -34,28 +34,26 @@ namespace memgraph::storage::v3::tests {
|
||||
class IndexTest : public testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
storage.StoreMapping({{1, "label"}, {2, "property"}, {3, "label1"}, {4, "label2"}, {5, "id"}, {6, "val"}});
|
||||
ASSERT_TRUE(
|
||||
storage.CreateSchema(primary_label, {storage::v3::SchemaProperty{primary_property, common::SchemaType::INT}}));
|
||||
}
|
||||
|
||||
NameIdMapper id_mapper;
|
||||
const std::vector<PropertyValue> pk{PropertyValue{0}};
|
||||
const LabelId primary_label{NameToLabelId("label")};
|
||||
const LabelId primary_label{LabelId::FromUint(1)};
|
||||
Shard storage{primary_label, pk, std::nullopt};
|
||||
const PropertyId primary_property{NameToPropertyId("property")};
|
||||
const PropertyId primary_property{PropertyId::FromUint(2)};
|
||||
|
||||
const PropertyId prop_id{NameToPropertyId("id")};
|
||||
const PropertyId prop_val{NameToPropertyId("val")};
|
||||
const LabelId label1{NameToLabelId("label1")};
|
||||
const LabelId label2{NameToLabelId("label2")};
|
||||
const LabelId label1{LabelId::FromUint(3)};
|
||||
const LabelId label2{LabelId::FromUint(4)};
|
||||
const PropertyId prop_id{PropertyId::FromUint(5)};
|
||||
const PropertyId prop_val{PropertyId::FromUint(6)};
|
||||
int primary_key_id{0};
|
||||
int vertex_id{0};
|
||||
|
||||
LabelId NameToLabelId(std::string_view label_name) { return LabelId::FromUint(id_mapper.NameToId(label_name)); }
|
||||
LabelId NameToLabelId(std::string_view label_name) { return storage.NameToLabel(label_name); }
|
||||
|
||||
PropertyId NameToPropertyId(std::string_view property_name) {
|
||||
return PropertyId::FromUint(id_mapper.NameToId(property_name));
|
||||
}
|
||||
PropertyId NameToPropertyId(std::string_view property_name) { return storage.NameToProperty(property_name); }
|
||||
|
||||
VertexAccessor CreateVertex(Shard::Accessor *accessor) {
|
||||
auto vertex = *accessor->CreateVertexAndValidate(
|
||||
|
@ -34,13 +34,12 @@ namespace memgraph::storage::v3::tests {
|
||||
|
||||
class SchemaTest : public testing::Test {
|
||||
private:
|
||||
NameIdMapper label_mapper_;
|
||||
NameIdMapper property_mapper_;
|
||||
NameIdMapper id_mapper_{{{1, "label1"}, {2, "label2"}, {3, "prop1"}, {4, "prop2"}}};
|
||||
|
||||
protected:
|
||||
LabelId NameToLabel(const std::string &name) { return LabelId::FromUint(label_mapper_.NameToId(name)); }
|
||||
LabelId NameToLabel(const std::string &name) { return LabelId::FromUint(id_mapper_.NameToId(name)); }
|
||||
|
||||
PropertyId NameToProperty(const std::string &name) { return PropertyId::FromUint(property_mapper_.NameToId(name)); }
|
||||
PropertyId NameToProperty(const std::string &name) { return PropertyId::FromUint(id_mapper_.NameToId(name)); }
|
||||
|
||||
PropertyId prop1{NameToProperty("prop1")};
|
||||
PropertyId prop2{NameToProperty("prop2")};
|
||||
@ -150,19 +149,18 @@ TEST_F(SchemaTest, TestSchemaDrop) {
|
||||
}
|
||||
|
||||
class SchemaValidatorTest : public testing::Test {
|
||||
private:
|
||||
NameIdMapper id_mapper_{{{1, "label1"}, {2, "label2"}, {3, "prop1"}, {4, "prop2"}, {5, "prop3"}}};
|
||||
|
||||
protected:
|
||||
void SetUp() override {
|
||||
ASSERT_TRUE(schemas.CreateSchema(label1, {schema_prop_string}));
|
||||
ASSERT_TRUE(schemas.CreateSchema(label2, {schema_prop_string, schema_prop_int, schema_prop_duration}));
|
||||
}
|
||||
|
||||
LabelId NameToLabel(const std::string &name) { return LabelId::FromUint(label_mapper_.NameToId(name)); }
|
||||
LabelId NameToLabel(const std::string &name) { return LabelId::FromUint(id_mapper_.NameToId(name)); }
|
||||
|
||||
PropertyId NameToProperty(const std::string &name) { return PropertyId::FromUint(property_mapper_.NameToId(name)); }
|
||||
|
||||
private:
|
||||
NameIdMapper label_mapper_;
|
||||
NameIdMapper property_mapper_;
|
||||
PropertyId NameToProperty(const std::string &name) { return PropertyId::FromUint(id_mapper_.NameToId(name)); }
|
||||
|
||||
protected:
|
||||
Schemas schemas;
|
||||
|
@ -32,6 +32,7 @@ namespace memgraph::storage::v3::tests {
|
||||
class StorageV3Accessor : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
storage.StoreMapping({{1, "label"}, {2, "property"}});
|
||||
ASSERT_TRUE(storage.CreateSchema(primary_label, {SchemaProperty{primary_property, common::SchemaType::INT}}));
|
||||
}
|
||||
|
||||
@ -43,17 +44,14 @@ class StorageV3Accessor : public ::testing::Test {
|
||||
return *vtx;
|
||||
}
|
||||
|
||||
LabelId NameToLabelId(std::string_view label_name) { return LabelId::FromUint(id_mapper.NameToId(label_name)); }
|
||||
LabelId NameToLabelId(std::string_view label_name) { return storage.NameToLabel(label_name); }
|
||||
|
||||
PropertyId NameToPropertyId(std::string_view property_name) {
|
||||
return PropertyId::FromUint(id_mapper.NameToId(property_name));
|
||||
}
|
||||
PropertyId NameToPropertyId(std::string_view property_name) { return storage.NameToProperty(property_name); }
|
||||
|
||||
const std::vector<PropertyValue> pk{PropertyValue{0}};
|
||||
NameIdMapper id_mapper;
|
||||
Shard storage{NameToLabelId("label"), pk, std::nullopt};
|
||||
const LabelId primary_label{NameToLabelId("label")};
|
||||
const PropertyId primary_property{NameToPropertyId("property")};
|
||||
const LabelId primary_label{LabelId::FromUint(1)};
|
||||
const PropertyId primary_property{PropertyId::FromUint(2)};
|
||||
Shard storage{primary_label, pk, std::nullopt};
|
||||
};
|
||||
|
||||
TEST_F(StorageV3Accessor, TestPrimaryLabel) {
|
||||
@ -91,6 +89,7 @@ TEST_F(StorageV3Accessor, TestPrimaryLabel) {
|
||||
}
|
||||
|
||||
TEST_F(StorageV3Accessor, TestAddLabels) {
|
||||
storage.StoreMapping({{1, "label"}, {2, "property"}, {3, "label1"}, {4, "label2"}, {5, "label3"}});
|
||||
{
|
||||
auto acc = storage.Access();
|
||||
const auto label1 = NameToLabelId("label1");
|
||||
@ -140,6 +139,8 @@ TEST_F(StorageV3Accessor, TestAddLabels) {
|
||||
}
|
||||
|
||||
TEST_F(StorageV3Accessor, TestRemoveLabels) {
|
||||
storage.StoreMapping({{1, "label"}, {2, "property"}, {3, "label1"}, {4, "label2"}, {5, "label3"}});
|
||||
|
||||
{
|
||||
auto acc = storage.Access();
|
||||
const auto label1 = NameToLabelId("label1");
|
||||
@ -185,6 +186,8 @@ TEST_F(StorageV3Accessor, TestRemoveLabels) {
|
||||
}
|
||||
|
||||
TEST_F(StorageV3Accessor, TestSetKeysAndProperties) {
|
||||
storage.StoreMapping({{1, "label"}, {2, "property"}, {3, "prop1"}});
|
||||
storage.StoreMapping({{1, "label"}, {2, "property"}, {3, "prop1"}});
|
||||
{
|
||||
auto acc = storage.Access();
|
||||
const PropertyId prop1{NameToPropertyId("prop1")};
|
||||
|
Loading…
Reference in New Issue
Block a user