Implement ClearProperties
for storage v2
Reviewers: teon.banek Reviewed By: teon.banek Subscribers: pullbot Differential Revision: https://phabricator.memgraph.io/D2537
This commit is contained in:
parent
df43ccea95
commit
9eb1f1d5cd
@ -52,7 +52,9 @@ class EdgeAccessor final {
|
||||
}
|
||||
|
||||
utils::BasicResult<storage::Error, void> ClearProperties() {
|
||||
throw utils::NotYetImplemented("ClearProperties");
|
||||
auto ret = impl_.ClearProperties();
|
||||
if (ret.HasError()) return ret.GetError();
|
||||
return {};
|
||||
}
|
||||
|
||||
VertexAccessor To() const;
|
||||
@ -118,7 +120,9 @@ class VertexAccessor final {
|
||||
}
|
||||
|
||||
utils::BasicResult<storage::Error, void> ClearProperties() {
|
||||
throw utils::NotYetImplemented("ClearProperties");
|
||||
auto ret = impl_.ClearProperties();
|
||||
if (ret.HasError()) return ret.GetError();
|
||||
return {};
|
||||
}
|
||||
|
||||
auto InEdges(storage::View view,
|
||||
|
@ -55,6 +55,27 @@ Result<bool> EdgeAccessor::SetProperty(PropertyId property,
|
||||
return !existed;
|
||||
}
|
||||
|
||||
Result<bool> EdgeAccessor::ClearProperties() {
|
||||
if (!config_.properties_on_edges) return Error::PROPERTIES_DISABLED;
|
||||
|
||||
std::lock_guard<utils::SpinLock> guard(edge_.ptr->lock);
|
||||
|
||||
if (!PrepareForWrite(transaction_, edge_.ptr))
|
||||
return Error::SERIALIZATION_ERROR;
|
||||
|
||||
if (edge_.ptr->deleted) return Error::DELETED_OBJECT;
|
||||
|
||||
bool removed = !edge_.ptr->properties.empty();
|
||||
for (const auto &property : edge_.ptr->properties) {
|
||||
CreateAndLinkDelta(transaction_, edge_.ptr, Delta::SetPropertyTag(),
|
||||
property.first, property.second);
|
||||
}
|
||||
|
||||
edge_.ptr->properties.clear();
|
||||
|
||||
return removed;
|
||||
}
|
||||
|
||||
Result<PropertyValue> EdgeAccessor::GetProperty(PropertyId property,
|
||||
View view) const {
|
||||
if (!config_.properties_on_edges) return PropertyValue();
|
||||
|
@ -43,6 +43,11 @@ class EdgeAccessor final {
|
||||
/// @throw std::bad_alloc
|
||||
Result<bool> SetProperty(PropertyId property, const PropertyValue &value);
|
||||
|
||||
/// Remove all properties and return `true` if any removal took place.
|
||||
/// `false` is returned if there were no properties to remove.
|
||||
/// @throw std::bad_alloc
|
||||
Result<bool> ClearProperties();
|
||||
|
||||
/// @throw std::bad_alloc
|
||||
Result<PropertyValue> GetProperty(PropertyId property, View view) const;
|
||||
|
||||
|
@ -221,6 +221,27 @@ Result<bool> VertexAccessor::SetProperty(PropertyId property,
|
||||
return !existed;
|
||||
}
|
||||
|
||||
Result<bool> VertexAccessor::ClearProperties() {
|
||||
std::lock_guard<utils::SpinLock> guard(vertex_->lock);
|
||||
|
||||
if (!PrepareForWrite(transaction_, vertex_))
|
||||
return Error::SERIALIZATION_ERROR;
|
||||
|
||||
if (vertex_->deleted) return Error::DELETED_OBJECT;
|
||||
|
||||
bool removed = !vertex_->properties.empty();
|
||||
for (const auto &property : vertex_->properties) {
|
||||
CreateAndLinkDelta(transaction_, vertex_, Delta::SetPropertyTag(),
|
||||
property.first, property.second);
|
||||
UpdateOnSetProperty(indices_, property.first, PropertyValue(), vertex_,
|
||||
*transaction_);
|
||||
}
|
||||
|
||||
vertex_->properties.clear();
|
||||
|
||||
return removed;
|
||||
}
|
||||
|
||||
Result<PropertyValue> VertexAccessor::GetProperty(PropertyId property,
|
||||
View view) const {
|
||||
bool deleted = false;
|
||||
|
@ -54,6 +54,11 @@ class VertexAccessor final {
|
||||
/// @throw std::bad_alloc
|
||||
Result<bool> SetProperty(PropertyId property, const PropertyValue &value);
|
||||
|
||||
/// Remove all properties and return `true` if any removal took place.
|
||||
/// `false` is returned if there were no properties to remove.
|
||||
/// @throw std::bad_alloc
|
||||
Result<bool> ClearProperties();
|
||||
|
||||
/// @throw std::bad_alloc
|
||||
Result<PropertyValue> GetProperty(PropertyId property, View view) const;
|
||||
|
||||
|
@ -1,9 +1,12 @@
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "storage/v2/storage.hpp"
|
||||
|
||||
using testing::UnorderedElementsAre;
|
||||
|
||||
size_t CountVertices(storage::Storage::Accessor *storage_accessor,
|
||||
storage::View view) {
|
||||
auto vertices = storage_accessor->Vertices(view);
|
||||
@ -2143,3 +2146,113 @@ TEST(StorageV2, VertexLabelPropertyMixed) {
|
||||
|
||||
ASSERT_FALSE(acc.Commit().HasError());
|
||||
}
|
||||
|
||||
TEST(StorageV2, VertexPropertyClear) {
|
||||
storage::Storage store;
|
||||
storage::Gid gid;
|
||||
auto property1 = store.NameToProperty("property1");
|
||||
auto property2 = store.NameToProperty("property2");
|
||||
{
|
||||
auto acc = store.Access();
|
||||
auto vertex = acc.CreateVertex();
|
||||
gid = vertex.Gid();
|
||||
|
||||
auto res = vertex.SetProperty(property1, storage::PropertyValue("value"));
|
||||
ASSERT_TRUE(res.HasValue());
|
||||
ASSERT_TRUE(res.GetValue());
|
||||
|
||||
ASSERT_FALSE(acc.Commit().HasError());
|
||||
}
|
||||
{
|
||||
auto acc = store.Access();
|
||||
auto vertex = acc.FindVertex(gid, storage::View::OLD);
|
||||
ASSERT_TRUE(vertex);
|
||||
|
||||
ASSERT_EQ(vertex->GetProperty(property1, storage::View::OLD)->ValueString(),
|
||||
"value");
|
||||
ASSERT_TRUE(vertex->GetProperty(property2, storage::View::OLD)->IsNull());
|
||||
ASSERT_THAT(vertex->Properties(storage::View::OLD).GetValue(),
|
||||
UnorderedElementsAre(
|
||||
std::pair(property1, storage::PropertyValue("value"))));
|
||||
|
||||
{
|
||||
auto ret = vertex->ClearProperties();
|
||||
ASSERT_TRUE(ret.HasValue());
|
||||
ASSERT_TRUE(ret.GetValue());
|
||||
}
|
||||
|
||||
ASSERT_TRUE(vertex->GetProperty(property1, storage::View::NEW)->IsNull());
|
||||
ASSERT_TRUE(vertex->GetProperty(property2, storage::View::NEW)->IsNull());
|
||||
ASSERT_EQ(vertex->Properties(storage::View::NEW).GetValue().size(), 0);
|
||||
|
||||
{
|
||||
auto ret = vertex->ClearProperties();
|
||||
ASSERT_TRUE(ret.HasValue());
|
||||
ASSERT_FALSE(ret.GetValue());
|
||||
}
|
||||
|
||||
ASSERT_TRUE(vertex->GetProperty(property1, storage::View::NEW)->IsNull());
|
||||
ASSERT_TRUE(vertex->GetProperty(property2, storage::View::NEW)->IsNull());
|
||||
ASSERT_EQ(vertex->Properties(storage::View::NEW).GetValue().size(), 0);
|
||||
|
||||
acc.Abort();
|
||||
}
|
||||
{
|
||||
auto acc = store.Access();
|
||||
auto vertex = acc.FindVertex(gid, storage::View::OLD);
|
||||
ASSERT_TRUE(vertex);
|
||||
|
||||
auto res = vertex->SetProperty(property2, storage::PropertyValue(42));
|
||||
ASSERT_TRUE(res.HasValue());
|
||||
ASSERT_TRUE(res.GetValue());
|
||||
|
||||
ASSERT_FALSE(acc.Commit().HasError());
|
||||
}
|
||||
{
|
||||
auto acc = store.Access();
|
||||
auto vertex = acc.FindVertex(gid, storage::View::OLD);
|
||||
ASSERT_TRUE(vertex);
|
||||
|
||||
ASSERT_EQ(vertex->GetProperty(property1, storage::View::OLD)->ValueString(),
|
||||
"value");
|
||||
ASSERT_EQ(vertex->GetProperty(property2, storage::View::OLD)->ValueInt(),
|
||||
42);
|
||||
ASSERT_THAT(vertex->Properties(storage::View::OLD).GetValue(),
|
||||
UnorderedElementsAre(
|
||||
std::pair(property1, storage::PropertyValue("value")),
|
||||
std::pair(property2, storage::PropertyValue(42))));
|
||||
|
||||
{
|
||||
auto ret = vertex->ClearProperties();
|
||||
ASSERT_TRUE(ret.HasValue());
|
||||
ASSERT_TRUE(ret.GetValue());
|
||||
}
|
||||
|
||||
ASSERT_TRUE(vertex->GetProperty(property1, storage::View::NEW)->IsNull());
|
||||
ASSERT_TRUE(vertex->GetProperty(property2, storage::View::NEW)->IsNull());
|
||||
ASSERT_EQ(vertex->Properties(storage::View::NEW).GetValue().size(), 0);
|
||||
|
||||
{
|
||||
auto ret = vertex->ClearProperties();
|
||||
ASSERT_TRUE(ret.HasValue());
|
||||
ASSERT_FALSE(ret.GetValue());
|
||||
}
|
||||
|
||||
ASSERT_TRUE(vertex->GetProperty(property1, storage::View::NEW)->IsNull());
|
||||
ASSERT_TRUE(vertex->GetProperty(property2, storage::View::NEW)->IsNull());
|
||||
ASSERT_EQ(vertex->Properties(storage::View::NEW).GetValue().size(), 0);
|
||||
|
||||
ASSERT_FALSE(acc.Commit().HasError());
|
||||
}
|
||||
{
|
||||
auto acc = store.Access();
|
||||
auto vertex = acc.FindVertex(gid, storage::View::OLD);
|
||||
ASSERT_TRUE(vertex);
|
||||
|
||||
ASSERT_TRUE(vertex->GetProperty(property1, storage::View::NEW)->IsNull());
|
||||
ASSERT_TRUE(vertex->GetProperty(property2, storage::View::NEW)->IsNull());
|
||||
ASSERT_EQ(vertex->Properties(storage::View::NEW).GetValue().size(), 0);
|
||||
|
||||
acc.Abort();
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,8 @@
|
||||
|
||||
#include "storage/v2/storage.hpp"
|
||||
|
||||
using testing::UnorderedElementsAre;
|
||||
|
||||
class StorageEdgeTest : public ::testing::TestWithParam<bool> {};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(EdgesWithProperties, StorageEdgeTest,
|
||||
@ -5108,6 +5110,124 @@ TEST(StorageWithProperties, EdgePropertySerializationError) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(StorageWithProperties, EdgePropertyClear) {
|
||||
storage::Storage store({.items = {.properties_on_edges = true}});
|
||||
storage::Gid gid;
|
||||
auto property1 = store.NameToProperty("property1");
|
||||
auto property2 = store.NameToProperty("property2");
|
||||
{
|
||||
auto acc = store.Access();
|
||||
auto vertex = acc.CreateVertex();
|
||||
gid = vertex.Gid();
|
||||
auto et = acc.NameToEdgeType("et5");
|
||||
auto edge = acc.CreateEdge(&vertex, &vertex, et).GetValue();
|
||||
ASSERT_EQ(edge.EdgeType(), et);
|
||||
ASSERT_EQ(edge.FromVertex(), vertex);
|
||||
ASSERT_EQ(edge.ToVertex(), vertex);
|
||||
|
||||
auto res = edge.SetProperty(property1, storage::PropertyValue("value"));
|
||||
ASSERT_TRUE(res.HasValue());
|
||||
ASSERT_TRUE(res.GetValue());
|
||||
|
||||
ASSERT_FALSE(acc.Commit().HasError());
|
||||
}
|
||||
{
|
||||
auto acc = store.Access();
|
||||
auto vertex = acc.FindVertex(gid, storage::View::OLD);
|
||||
ASSERT_TRUE(vertex);
|
||||
auto edge = vertex->OutEdges({}, storage::View::NEW).GetValue()[0];
|
||||
|
||||
ASSERT_EQ(edge.GetProperty(property1, storage::View::OLD)->ValueString(),
|
||||
"value");
|
||||
ASSERT_TRUE(edge.GetProperty(property2, storage::View::OLD)->IsNull());
|
||||
ASSERT_THAT(edge.Properties(storage::View::OLD).GetValue(),
|
||||
UnorderedElementsAre(
|
||||
std::pair(property1, storage::PropertyValue("value"))));
|
||||
|
||||
{
|
||||
auto ret = edge.ClearProperties();
|
||||
ASSERT_TRUE(ret.HasValue());
|
||||
ASSERT_TRUE(ret.GetValue());
|
||||
}
|
||||
|
||||
ASSERT_TRUE(edge.GetProperty(property1, storage::View::NEW)->IsNull());
|
||||
ASSERT_TRUE(edge.GetProperty(property2, storage::View::NEW)->IsNull());
|
||||
ASSERT_EQ(edge.Properties(storage::View::NEW).GetValue().size(), 0);
|
||||
|
||||
{
|
||||
auto ret = edge.ClearProperties();
|
||||
ASSERT_TRUE(ret.HasValue());
|
||||
ASSERT_FALSE(ret.GetValue());
|
||||
}
|
||||
|
||||
ASSERT_TRUE(edge.GetProperty(property1, storage::View::NEW)->IsNull());
|
||||
ASSERT_TRUE(edge.GetProperty(property2, storage::View::NEW)->IsNull());
|
||||
ASSERT_EQ(edge.Properties(storage::View::NEW).GetValue().size(), 0);
|
||||
|
||||
acc.Abort();
|
||||
}
|
||||
{
|
||||
auto acc = store.Access();
|
||||
auto vertex = acc.FindVertex(gid, storage::View::OLD);
|
||||
ASSERT_TRUE(vertex);
|
||||
auto edge = vertex->OutEdges({}, storage::View::NEW).GetValue()[0];
|
||||
|
||||
auto res = edge.SetProperty(property2, storage::PropertyValue(42));
|
||||
ASSERT_TRUE(res.HasValue());
|
||||
ASSERT_TRUE(res.GetValue());
|
||||
|
||||
ASSERT_FALSE(acc.Commit().HasError());
|
||||
}
|
||||
{
|
||||
auto acc = store.Access();
|
||||
auto vertex = acc.FindVertex(gid, storage::View::OLD);
|
||||
ASSERT_TRUE(vertex);
|
||||
auto edge = vertex->OutEdges({}, storage::View::NEW).GetValue()[0];
|
||||
|
||||
ASSERT_EQ(edge.GetProperty(property1, storage::View::OLD)->ValueString(),
|
||||
"value");
|
||||
ASSERT_EQ(edge.GetProperty(property2, storage::View::OLD)->ValueInt(), 42);
|
||||
ASSERT_THAT(edge.Properties(storage::View::OLD).GetValue(),
|
||||
UnorderedElementsAre(
|
||||
std::pair(property1, storage::PropertyValue("value")),
|
||||
std::pair(property2, storage::PropertyValue(42))));
|
||||
|
||||
{
|
||||
auto ret = edge.ClearProperties();
|
||||
ASSERT_TRUE(ret.HasValue());
|
||||
ASSERT_TRUE(ret.GetValue());
|
||||
}
|
||||
|
||||
ASSERT_TRUE(edge.GetProperty(property1, storage::View::NEW)->IsNull());
|
||||
ASSERT_TRUE(edge.GetProperty(property2, storage::View::NEW)->IsNull());
|
||||
ASSERT_EQ(edge.Properties(storage::View::NEW).GetValue().size(), 0);
|
||||
|
||||
{
|
||||
auto ret = edge.ClearProperties();
|
||||
ASSERT_TRUE(ret.HasValue());
|
||||
ASSERT_FALSE(ret.GetValue());
|
||||
}
|
||||
|
||||
ASSERT_TRUE(edge.GetProperty(property1, storage::View::NEW)->IsNull());
|
||||
ASSERT_TRUE(edge.GetProperty(property2, storage::View::NEW)->IsNull());
|
||||
ASSERT_EQ(edge.Properties(storage::View::NEW).GetValue().size(), 0);
|
||||
|
||||
ASSERT_FALSE(acc.Commit().HasError());
|
||||
}
|
||||
{
|
||||
auto acc = store.Access();
|
||||
auto vertex = acc.FindVertex(gid, storage::View::OLD);
|
||||
ASSERT_TRUE(vertex);
|
||||
auto edge = vertex->OutEdges({}, storage::View::NEW).GetValue()[0];
|
||||
|
||||
ASSERT_TRUE(edge.GetProperty(property1, storage::View::NEW)->IsNull());
|
||||
ASSERT_TRUE(edge.GetProperty(property2, storage::View::NEW)->IsNull());
|
||||
ASSERT_EQ(edge.Properties(storage::View::NEW).GetValue().size(), 0);
|
||||
|
||||
acc.Abort();
|
||||
}
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(hicpp-special-member-functions)
|
||||
TEST(StorageWithoutProperties, EdgePropertyAbort) {
|
||||
storage::Storage store({.items = {.properties_on_edges = false}});
|
||||
@ -5178,3 +5298,30 @@ TEST(StorageWithoutProperties, EdgePropertyAbort) {
|
||||
acc.Abort();
|
||||
}
|
||||
}
|
||||
|
||||
TEST(StorageWithoutProperties, EdgePropertyClear) {
|
||||
storage::Storage store({.items = {.properties_on_edges = false}});
|
||||
storage::Gid gid;
|
||||
{
|
||||
auto acc = store.Access();
|
||||
auto vertex = acc.CreateVertex();
|
||||
gid = vertex.Gid();
|
||||
auto et = acc.NameToEdgeType("et5");
|
||||
auto edge = acc.CreateEdge(&vertex, &vertex, et).GetValue();
|
||||
ASSERT_EQ(edge.EdgeType(), et);
|
||||
ASSERT_EQ(edge.FromVertex(), vertex);
|
||||
ASSERT_EQ(edge.ToVertex(), vertex);
|
||||
ASSERT_FALSE(acc.Commit().HasError());
|
||||
}
|
||||
{
|
||||
auto acc = store.Access();
|
||||
auto vertex = acc.FindVertex(gid, storage::View::OLD);
|
||||
ASSERT_TRUE(vertex);
|
||||
auto edge = vertex->OutEdges({}, storage::View::NEW).GetValue()[0];
|
||||
|
||||
ASSERT_EQ(edge.ClearProperties().GetError(),
|
||||
storage::Error::PROPERTIES_DISABLED);
|
||||
|
||||
acc.Abort();
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user