Implement properties for edges in storage v2

Reviewers: mtomic, teon.banek

Reviewed By: mtomic

Subscribers: pullbot

Differential Revision: https://phabricator.memgraph.io/D2187
This commit is contained in:
Matej Ferencevic 2019-07-08 15:36:06 +02:00
parent 5b8e7ff432
commit b1f7bbf051
5 changed files with 674 additions and 3 deletions

View File

@ -20,8 +20,7 @@ struct Edge {
Gid gid;
// TODO: add
// std::unordered_map<uint64_t, storage::PropertyValue> properties;
std::unordered_map<uint64_t, storage::PropertyValue> properties;
utils::SpinLock lock;
bool deleted;

View File

@ -15,4 +15,133 @@ VertexAccessor EdgeAccessor::ToVertex() {
return VertexAccessor{to_vertex_, transaction_};
}
Result<bool> EdgeAccessor::SetProperty(uint64_t property,
const PropertyValue &value) {
std::lock_guard<utils::SpinLock> guard(edge_->lock);
if (!PrepareForWrite(transaction_, edge_))
return Result<bool>{Error::SERIALIZATION_ERROR};
if (edge_->deleted) return Result<bool>{Error::DELETED_OBJECT};
auto it = edge_->properties.find(property);
bool existed = it != edge_->properties.end();
if (it != edge_->properties.end()) {
CreateAndLinkDelta(transaction_, edge_, Delta::SetPropertyTag(), property,
it->second);
if (value.IsNull()) {
// remove the property
edge_->properties.erase(it);
} else {
// set the value
it->second = value;
}
} else {
CreateAndLinkDelta(transaction_, edge_, Delta::SetPropertyTag(), property,
PropertyValue());
if (!value.IsNull()) {
edge_->properties.emplace(property, value);
}
}
return Result<bool>{existed};
}
Result<PropertyValue> EdgeAccessor::GetProperty(uint64_t property, View view) {
bool deleted = false;
PropertyValue value;
Delta *delta = nullptr;
{
std::lock_guard<utils::SpinLock> guard(edge_->lock);
deleted = edge_->deleted;
auto it = edge_->properties.find(property);
if (it != edge_->properties.end()) {
value = it->second;
}
delta = edge_->delta;
}
ApplyDeltasForRead(transaction_, delta, view,
[&deleted, &value, property](const Delta &delta) {
switch (delta.action) {
case Delta::Action::SET_PROPERTY: {
if (delta.property.key == property) {
value = delta.property.value;
}
break;
}
case Delta::Action::DELETE_OBJECT: {
LOG(FATAL) << "Invalid accessor!";
break;
}
case Delta::Action::RECREATE_OBJECT: {
deleted = false;
break;
}
case Delta::Action::ADD_LABEL:
case Delta::Action::REMOVE_LABEL:
case Delta::Action::ADD_IN_EDGE:
case Delta::Action::ADD_OUT_EDGE:
case Delta::Action::REMOVE_IN_EDGE:
case Delta::Action::REMOVE_OUT_EDGE:
break;
}
});
if (deleted) return Result<PropertyValue>{Error::DELETED_OBJECT};
return Result<PropertyValue>{std::move(value)};
}
Result<std::unordered_map<uint64_t, PropertyValue>> EdgeAccessor::Properties(
View view) {
std::unordered_map<uint64_t, PropertyValue> properties;
bool deleted = false;
Delta *delta = nullptr;
{
std::lock_guard<utils::SpinLock> guard(edge_->lock);
deleted = edge_->deleted;
properties = edge_->properties;
delta = edge_->delta;
}
ApplyDeltasForRead(
transaction_, delta, view, [&deleted, &properties](const Delta &delta) {
switch (delta.action) {
case Delta::Action::SET_PROPERTY: {
auto it = properties.find(delta.property.key);
if (it != properties.end()) {
if (delta.property.value.IsNull()) {
// remove the property
properties.erase(it);
} else {
// set the value
it->second = delta.property.value;
}
} else if (!delta.property.value.IsNull()) {
properties.emplace(delta.property.key, delta.property.value);
}
break;
}
case Delta::Action::DELETE_OBJECT: {
LOG(FATAL) << "Invalid accessor!";
break;
}
case Delta::Action::RECREATE_OBJECT: {
deleted = false;
break;
}
case Delta::Action::ADD_LABEL:
case Delta::Action::REMOVE_LABEL:
case Delta::Action::ADD_IN_EDGE:
case Delta::Action::ADD_OUT_EDGE:
case Delta::Action::REMOVE_IN_EDGE:
case Delta::Action::REMOVE_OUT_EDGE:
break;
}
});
if (deleted) {
return Result<std::unordered_map<uint64_t, PropertyValue>>{
Error::DELETED_OBJECT};
}
return Result<std::unordered_map<uint64_t, PropertyValue>>{
std::move(properties)};
}
} // namespace storage

View File

@ -33,6 +33,12 @@ class EdgeAccessor final {
uint64_t EdgeType() const { return edge_type_; }
Result<bool> SetProperty(uint64_t property, const PropertyValue &value);
Result<PropertyValue> GetProperty(uint64_t property, View view);
Result<std::unordered_map<uint64_t, PropertyValue>> Properties(View view);
Gid Gid() const { return edge_->gid; }
bool operator==(const EdgeAccessor &other) const {

View File

@ -407,6 +407,22 @@ void Storage::Accessor::Abort() {
current->timestamp->load(std::memory_order_acquire) ==
transaction_->transaction_id) {
switch (current->action) {
case Delta::Action::SET_PROPERTY: {
auto it = edge->properties.find(current->property.key);
if (it != edge->properties.end()) {
if (current->property.value.IsNull()) {
// remove the property
edge->properties.erase(it);
} else {
// set the value
it->second = current->property.value;
}
} else if (!current->property.value.IsNull()) {
edge->properties.emplace(current->property.key,
current->property.value);
}
break;
}
case Delta::Action::DELETE_OBJECT: {
auto acc = storage_->edges_.access();
CHECK(acc.remove(edge->gid)) << "Invalid database state!";
@ -418,7 +434,6 @@ void Storage::Accessor::Abort() {
}
case Delta::Action::REMOVE_LABEL:
case Delta::Action::ADD_LABEL:
case Delta::Action::SET_PROPERTY:
case Delta::Action::ADD_IN_EDGE:
case Delta::Action::ADD_OUT_EDGE:
case Delta::Action::REMOVE_IN_EDGE:

View File

@ -4622,3 +4622,525 @@ TEST(StorageV2, VertexDetachDeleteMultipleAbort) {
}
}
}
// NOLINTNEXTLINE(hicpp-special-member-functions)
TEST(StorageV2, EdgePropertyCommit) {
storage::Storage store;
storage::Gid gid =
storage::Gid::FromUint(std::numeric_limits<uint64_t>::max());
{
auto acc = store.Access();
auto vertex = acc.CreateVertex();
gid = vertex.Gid();
auto edge = acc.CreateEdge(&vertex, &vertex, 5).GetReturn();
ASSERT_EQ(edge.EdgeType(), 5);
ASSERT_EQ(edge.FromVertex(), vertex);
ASSERT_EQ(edge.ToVertex(), vertex);
ASSERT_TRUE(edge.GetProperty(5, storage::View::NEW).GetReturn().IsNull());
ASSERT_EQ(edge.Properties(storage::View::NEW).GetReturn().size(), 0);
{
auto res = edge.SetProperty(5, storage::PropertyValue("temporary"));
ASSERT_TRUE(res.IsReturn());
ASSERT_FALSE(res.GetReturn());
}
ASSERT_EQ(edge.GetProperty(5, storage::View::NEW).GetReturn().ValueString(),
"temporary");
{
auto properties = edge.Properties(storage::View::NEW).GetReturn();
ASSERT_EQ(properties.size(), 1);
ASSERT_EQ(properties[5].ValueString(), "temporary");
}
{
auto res = edge.SetProperty(5, storage::PropertyValue("nandare"));
ASSERT_TRUE(res.IsReturn());
ASSERT_TRUE(res.GetReturn());
}
ASSERT_EQ(edge.GetProperty(5, storage::View::NEW).GetReturn().ValueString(),
"nandare");
{
auto properties = edge.Properties(storage::View::NEW).GetReturn();
ASSERT_EQ(properties.size(), 1);
ASSERT_EQ(properties[5].ValueString(), "nandare");
}
acc.Commit();
}
{
auto acc = store.Access();
auto vertex = acc.FindVertex(gid, storage::View::OLD);
ASSERT_TRUE(vertex);
auto [edge_type, other_vertex, edge] =
vertex->OutEdges({}, storage::View::NEW).GetReturn()[0];
ASSERT_EQ(edge.GetProperty(5, storage::View::OLD).GetReturn().ValueString(),
"nandare");
{
auto properties = edge.Properties(storage::View::OLD).GetReturn();
ASSERT_EQ(properties.size(), 1);
ASSERT_EQ(properties[5].ValueString(), "nandare");
}
ASSERT_EQ(edge.GetProperty(5, storage::View::NEW).GetReturn().ValueString(),
"nandare");
{
auto properties = edge.Properties(storage::View::NEW).GetReturn();
ASSERT_EQ(properties.size(), 1);
ASSERT_EQ(properties[5].ValueString(), "nandare");
}
ASSERT_TRUE(edge.GetProperty(10, storage::View::OLD).GetReturn().IsNull());
ASSERT_TRUE(edge.GetProperty(10, storage::View::NEW).GetReturn().IsNull());
acc.Abort();
}
{
auto acc = store.Access();
auto vertex = acc.FindVertex(gid, storage::View::OLD);
ASSERT_TRUE(vertex);
auto [edge_type, other_vertex, edge] =
vertex->OutEdges({}, storage::View::NEW).GetReturn()[0];
{
auto res = edge.SetProperty(5, storage::PropertyValue());
ASSERT_TRUE(res.IsReturn());
ASSERT_TRUE(res.GetReturn());
}
ASSERT_EQ(edge.GetProperty(5, storage::View::OLD).GetReturn().ValueString(),
"nandare");
{
auto properties = edge.Properties(storage::View::OLD).GetReturn();
ASSERT_EQ(properties.size(), 1);
ASSERT_EQ(properties[5].ValueString(), "nandare");
}
ASSERT_TRUE(edge.GetProperty(5, storage::View::NEW).GetReturn().IsNull());
ASSERT_EQ(edge.Properties(storage::View::NEW).GetReturn().size(), 0);
{
auto res = edge.SetProperty(5, storage::PropertyValue());
ASSERT_TRUE(res.IsReturn());
ASSERT_FALSE(res.GetReturn());
}
acc.Commit();
}
{
auto acc = store.Access();
auto vertex = acc.FindVertex(gid, storage::View::OLD);
ASSERT_TRUE(vertex);
auto [edge_type, other_vertex, edge] =
vertex->OutEdges({}, storage::View::NEW).GetReturn()[0];
ASSERT_TRUE(edge.GetProperty(5, storage::View::OLD).GetReturn().IsNull());
ASSERT_TRUE(edge.GetProperty(5, storage::View::NEW).GetReturn().IsNull());
ASSERT_EQ(edge.Properties(storage::View::OLD).GetReturn().size(), 0);
ASSERT_EQ(edge.Properties(storage::View::NEW).GetReturn().size(), 0);
ASSERT_TRUE(edge.GetProperty(10, storage::View::OLD).GetReturn().IsNull());
ASSERT_TRUE(edge.GetProperty(10, storage::View::NEW).GetReturn().IsNull());
acc.Abort();
}
}
// NOLINTNEXTLINE(hicpp-special-member-functions)
TEST(StorageV2, EdgePropertyAbort) {
storage::Storage store;
storage::Gid gid =
storage::Gid::FromUint(std::numeric_limits<uint64_t>::max());
// Create the vertex.
{
auto acc = store.Access();
auto vertex = acc.CreateVertex();
gid = vertex.Gid();
auto edge = acc.CreateEdge(&vertex, &vertex, 5).GetReturn();
ASSERT_EQ(edge.EdgeType(), 5);
ASSERT_EQ(edge.FromVertex(), vertex);
ASSERT_EQ(edge.ToVertex(), vertex);
acc.Commit();
}
// Set property 5 to "nandare", but abort the transaction.
{
auto acc = store.Access();
auto vertex = acc.FindVertex(gid, storage::View::OLD);
ASSERT_TRUE(vertex);
auto [edge_type, other_vertex, edge] =
vertex->OutEdges({}, storage::View::NEW).GetReturn()[0];
ASSERT_TRUE(edge.GetProperty(5, storage::View::NEW).GetReturn().IsNull());
ASSERT_EQ(edge.Properties(storage::View::NEW).GetReturn().size(), 0);
{
auto res = edge.SetProperty(5, storage::PropertyValue("temporary"));
ASSERT_TRUE(res.IsReturn());
ASSERT_FALSE(res.GetReturn());
}
ASSERT_EQ(edge.GetProperty(5, storage::View::NEW).GetReturn().ValueString(),
"temporary");
{
auto properties = edge.Properties(storage::View::NEW).GetReturn();
ASSERT_EQ(properties.size(), 1);
ASSERT_EQ(properties[5].ValueString(), "temporary");
}
{
auto res = edge.SetProperty(5, storage::PropertyValue("nandare"));
ASSERT_TRUE(res.IsReturn());
ASSERT_TRUE(res.GetReturn());
}
ASSERT_EQ(edge.GetProperty(5, storage::View::NEW).GetReturn().ValueString(),
"nandare");
{
auto properties = edge.Properties(storage::View::NEW).GetReturn();
ASSERT_EQ(properties.size(), 1);
ASSERT_EQ(properties[5].ValueString(), "nandare");
}
acc.Abort();
}
// Check that property 5 is null.
{
auto acc = store.Access();
auto vertex = acc.FindVertex(gid, storage::View::OLD);
ASSERT_TRUE(vertex);
auto [edge_type, other_vertex, edge] =
vertex->OutEdges({}, storage::View::NEW).GetReturn()[0];
ASSERT_TRUE(edge.GetProperty(5, storage::View::OLD).GetReturn().IsNull());
ASSERT_TRUE(edge.GetProperty(5, storage::View::NEW).GetReturn().IsNull());
ASSERT_EQ(edge.Properties(storage::View::OLD).GetReturn().size(), 0);
ASSERT_EQ(edge.Properties(storage::View::NEW).GetReturn().size(), 0);
ASSERT_TRUE(edge.GetProperty(10, storage::View::OLD).GetReturn().IsNull());
ASSERT_TRUE(edge.GetProperty(10, storage::View::NEW).GetReturn().IsNull());
acc.Abort();
}
// Set property 5 to "nandare".
{
auto acc = store.Access();
auto vertex = acc.FindVertex(gid, storage::View::OLD);
ASSERT_TRUE(vertex);
auto [edge_type, other_vertex, edge] =
vertex->OutEdges({}, storage::View::NEW).GetReturn()[0];
ASSERT_TRUE(edge.GetProperty(5, storage::View::NEW).GetReturn().IsNull());
ASSERT_EQ(edge.Properties(storage::View::NEW).GetReturn().size(), 0);
{
auto res = edge.SetProperty(5, storage::PropertyValue("temporary"));
ASSERT_TRUE(res.IsReturn());
ASSERT_FALSE(res.GetReturn());
}
ASSERT_EQ(edge.GetProperty(5, storage::View::NEW).GetReturn().ValueString(),
"temporary");
{
auto properties = edge.Properties(storage::View::NEW).GetReturn();
ASSERT_EQ(properties.size(), 1);
ASSERT_EQ(properties[5].ValueString(), "temporary");
}
{
auto res = edge.SetProperty(5, storage::PropertyValue("nandare"));
ASSERT_TRUE(res.IsReturn());
ASSERT_TRUE(res.GetReturn());
}
ASSERT_EQ(edge.GetProperty(5, storage::View::NEW).GetReturn().ValueString(),
"nandare");
{
auto properties = edge.Properties(storage::View::NEW).GetReturn();
ASSERT_EQ(properties.size(), 1);
ASSERT_EQ(properties[5].ValueString(), "nandare");
}
acc.Commit();
}
// Check that property 5 is "nandare".
{
auto acc = store.Access();
auto vertex = acc.FindVertex(gid, storage::View::OLD);
ASSERT_TRUE(vertex);
auto [edge_type, other_vertex, edge] =
vertex->OutEdges({}, storage::View::NEW).GetReturn()[0];
ASSERT_EQ(edge.GetProperty(5, storage::View::OLD).GetReturn().ValueString(),
"nandare");
{
auto properties = edge.Properties(storage::View::OLD).GetReturn();
ASSERT_EQ(properties.size(), 1);
ASSERT_EQ(properties[5].ValueString(), "nandare");
}
ASSERT_EQ(edge.GetProperty(5, storage::View::NEW).GetReturn().ValueString(),
"nandare");
{
auto properties = edge.Properties(storage::View::NEW).GetReturn();
ASSERT_EQ(properties.size(), 1);
ASSERT_EQ(properties[5].ValueString(), "nandare");
}
ASSERT_TRUE(edge.GetProperty(10, storage::View::OLD).GetReturn().IsNull());
ASSERT_TRUE(edge.GetProperty(10, storage::View::NEW).GetReturn().IsNull());
acc.Abort();
}
// Set property 5 to null, but abort the transaction.
{
auto acc = store.Access();
auto vertex = acc.FindVertex(gid, storage::View::OLD);
ASSERT_TRUE(vertex);
auto [edge_type, other_vertex, edge] =
vertex->OutEdges({}, storage::View::NEW).GetReturn()[0];
ASSERT_EQ(edge.GetProperty(5, storage::View::OLD).GetReturn().ValueString(),
"nandare");
{
auto properties = edge.Properties(storage::View::OLD).GetReturn();
ASSERT_EQ(properties.size(), 1);
ASSERT_EQ(properties[5].ValueString(), "nandare");
}
ASSERT_EQ(edge.GetProperty(5, storage::View::NEW).GetReturn().ValueString(),
"nandare");
{
auto properties = edge.Properties(storage::View::NEW).GetReturn();
ASSERT_EQ(properties.size(), 1);
ASSERT_EQ(properties[5].ValueString(), "nandare");
}
{
auto res = edge.SetProperty(5, storage::PropertyValue());
ASSERT_TRUE(res.IsReturn());
ASSERT_TRUE(res.GetReturn());
}
ASSERT_EQ(edge.GetProperty(5, storage::View::OLD).GetReturn().ValueString(),
"nandare");
{
auto properties = edge.Properties(storage::View::OLD).GetReturn();
ASSERT_EQ(properties.size(), 1);
ASSERT_EQ(properties[5].ValueString(), "nandare");
}
ASSERT_TRUE(edge.GetProperty(5, storage::View::NEW).GetReturn().IsNull());
ASSERT_EQ(edge.Properties(storage::View::NEW).GetReturn().size(), 0);
acc.Abort();
}
// Check that property 5 is "nandare".
{
auto acc = store.Access();
auto vertex = acc.FindVertex(gid, storage::View::OLD);
ASSERT_TRUE(vertex);
auto [edge_type, other_vertex, edge] =
vertex->OutEdges({}, storage::View::NEW).GetReturn()[0];
ASSERT_EQ(edge.GetProperty(5, storage::View::OLD).GetReturn().ValueString(),
"nandare");
{
auto properties = edge.Properties(storage::View::OLD).GetReturn();
ASSERT_EQ(properties.size(), 1);
ASSERT_EQ(properties[5].ValueString(), "nandare");
}
ASSERT_EQ(edge.GetProperty(5, storage::View::NEW).GetReturn().ValueString(),
"nandare");
{
auto properties = edge.Properties(storage::View::NEW).GetReturn();
ASSERT_EQ(properties.size(), 1);
ASSERT_EQ(properties[5].ValueString(), "nandare");
}
ASSERT_TRUE(edge.GetProperty(10, storage::View::OLD).GetReturn().IsNull());
ASSERT_TRUE(edge.GetProperty(10, storage::View::NEW).GetReturn().IsNull());
acc.Abort();
}
// Set property 5 to null.
{
auto acc = store.Access();
auto vertex = acc.FindVertex(gid, storage::View::OLD);
ASSERT_TRUE(vertex);
auto [edge_type, other_vertex, edge] =
vertex->OutEdges({}, storage::View::NEW).GetReturn()[0];
ASSERT_EQ(edge.GetProperty(5, storage::View::OLD).GetReturn().ValueString(),
"nandare");
{
auto properties = edge.Properties(storage::View::OLD).GetReturn();
ASSERT_EQ(properties.size(), 1);
ASSERT_EQ(properties[5].ValueString(), "nandare");
}
ASSERT_EQ(edge.GetProperty(5, storage::View::NEW).GetReturn().ValueString(),
"nandare");
{
auto properties = edge.Properties(storage::View::NEW).GetReturn();
ASSERT_EQ(properties.size(), 1);
ASSERT_EQ(properties[5].ValueString(), "nandare");
}
{
auto res = edge.SetProperty(5, storage::PropertyValue());
ASSERT_TRUE(res.IsReturn());
ASSERT_TRUE(res.GetReturn());
}
ASSERT_EQ(edge.GetProperty(5, storage::View::OLD).GetReturn().ValueString(),
"nandare");
{
auto properties = edge.Properties(storage::View::OLD).GetReturn();
ASSERT_EQ(properties.size(), 1);
ASSERT_EQ(properties[5].ValueString(), "nandare");
}
ASSERT_TRUE(edge.GetProperty(5, storage::View::NEW).GetReturn().IsNull());
ASSERT_EQ(edge.Properties(storage::View::NEW).GetReturn().size(), 0);
acc.Commit();
}
// Check that property 5 is null.
{
auto acc = store.Access();
auto vertex = acc.FindVertex(gid, storage::View::OLD);
ASSERT_TRUE(vertex);
auto [edge_type, other_vertex, edge] =
vertex->OutEdges({}, storage::View::NEW).GetReturn()[0];
ASSERT_TRUE(edge.GetProperty(5, storage::View::OLD).GetReturn().IsNull());
ASSERT_TRUE(edge.GetProperty(5, storage::View::NEW).GetReturn().IsNull());
ASSERT_EQ(edge.Properties(storage::View::OLD).GetReturn().size(), 0);
ASSERT_EQ(edge.Properties(storage::View::NEW).GetReturn().size(), 0);
ASSERT_TRUE(edge.GetProperty(10, storage::View::OLD).GetReturn().IsNull());
ASSERT_TRUE(edge.GetProperty(10, storage::View::NEW).GetReturn().IsNull());
acc.Abort();
}
}
// NOLINTNEXTLINE(hicpp-special-member-functions)
TEST(StorageV2, EdgePropertySerializationError) {
storage::Storage store;
storage::Gid gid =
storage::Gid::FromUint(std::numeric_limits<uint64_t>::max());
{
auto acc = store.Access();
auto vertex = acc.CreateVertex();
gid = vertex.Gid();
auto edge = acc.CreateEdge(&vertex, &vertex, 5).GetReturn();
ASSERT_EQ(edge.EdgeType(), 5);
ASSERT_EQ(edge.FromVertex(), vertex);
ASSERT_EQ(edge.ToVertex(), vertex);
acc.Commit();
}
auto acc1 = store.Access();
auto acc2 = store.Access();
// Set property 1 to 123 in accessor 1.
{
auto vertex = acc1.FindVertex(gid, storage::View::OLD);
ASSERT_TRUE(vertex);
auto [edge_type, other_vertex, edge] =
vertex->OutEdges({}, storage::View::NEW).GetReturn()[0];
ASSERT_TRUE(edge.GetProperty(1, storage::View::OLD).GetReturn().IsNull());
ASSERT_TRUE(edge.GetProperty(1, storage::View::NEW).GetReturn().IsNull());
ASSERT_TRUE(edge.GetProperty(2, storage::View::OLD).GetReturn().IsNull());
ASSERT_TRUE(edge.GetProperty(2, storage::View::NEW).GetReturn().IsNull());
ASSERT_EQ(edge.Properties(storage::View::OLD).GetReturn().size(), 0);
ASSERT_EQ(edge.Properties(storage::View::NEW).GetReturn().size(), 0);
{
auto res = edge.SetProperty(1, storage::PropertyValue(123));
ASSERT_TRUE(res.IsReturn());
ASSERT_FALSE(res.GetReturn());
}
ASSERT_TRUE(edge.GetProperty(1, storage::View::OLD).GetReturn().IsNull());
ASSERT_EQ(edge.GetProperty(1, storage::View::NEW).GetReturn().ValueInt(),
123);
ASSERT_TRUE(edge.GetProperty(2, storage::View::OLD).GetReturn().IsNull());
ASSERT_TRUE(edge.GetProperty(2, storage::View::NEW).GetReturn().IsNull());
ASSERT_EQ(edge.Properties(storage::View::OLD).GetReturn().size(), 0);
{
auto properties = edge.Properties(storage::View::NEW).GetReturn();
ASSERT_EQ(properties.size(), 1);
ASSERT_EQ(properties[1].ValueInt(), 123);
}
}
// Set property 2 to "nandare" in accessor 2.
{
auto vertex = acc2.FindVertex(gid, storage::View::OLD);
ASSERT_TRUE(vertex);
auto [edge_type, other_vertex, edge] =
vertex->OutEdges({}, storage::View::NEW).GetReturn()[0];
ASSERT_TRUE(edge.GetProperty(1, storage::View::OLD).GetReturn().IsNull());
ASSERT_TRUE(edge.GetProperty(1, storage::View::NEW).GetReturn().IsNull());
ASSERT_TRUE(edge.GetProperty(2, storage::View::OLD).GetReturn().IsNull());
ASSERT_TRUE(edge.GetProperty(2, storage::View::NEW).GetReturn().IsNull());
ASSERT_EQ(edge.Properties(storage::View::OLD).GetReturn().size(), 0);
ASSERT_EQ(edge.Properties(storage::View::NEW).GetReturn().size(), 0);
{
auto res = edge.SetProperty(2, storage::PropertyValue("nandare"));
ASSERT_TRUE(res.IsError());
ASSERT_EQ(res.GetError(), storage::Error::SERIALIZATION_ERROR);
}
}
// Finalize both accessors.
acc1.Commit();
acc2.Abort();
// Check which properties exist.
{
auto acc = store.Access();
auto vertex = acc.FindVertex(gid, storage::View::OLD);
ASSERT_TRUE(vertex);
auto [edge_type, other_vertex, edge] =
vertex->OutEdges({}, storage::View::NEW).GetReturn()[0];
ASSERT_EQ(edge.GetProperty(1, storage::View::OLD).GetReturn().ValueInt(),
123);
ASSERT_TRUE(edge.GetProperty(2, storage::View::OLD).GetReturn().IsNull());
{
auto properties = edge.Properties(storage::View::OLD).GetReturn();
ASSERT_EQ(properties.size(), 1);
ASSERT_EQ(properties[1].ValueInt(), 123);
}
ASSERT_EQ(edge.GetProperty(1, storage::View::NEW).GetReturn().ValueInt(),
123);
ASSERT_TRUE(edge.GetProperty(2, storage::View::NEW).GetReturn().IsNull());
{
auto properties = edge.Properties(storage::View::NEW).GetReturn();
ASSERT_EQ(properties.size(), 1);
ASSERT_EQ(properties[1].ValueInt(), 123);
}
acc.Abort();
}
}