Constraint code cleanup

Summary: Refactor tests, remove some test cases, refactor some methods in `GraphDbAccessor`.

Reviewers: msantl

Reviewed By: msantl

Subscribers: pullbot

Differential Revision: https://phabricator.memgraph.io/D1933
This commit is contained in:
Vinko Kasljevic 2019-04-02 16:30:25 +02:00
parent dc231fe4e7
commit 2a63e2f12d
12 changed files with 191 additions and 224 deletions

View File

@ -0,0 +1,18 @@
/// @file
#pragma once
#include "utils/exceptions.hpp"
namespace database {
/// Thrown when creating an index which already exists.
class IndexExistsException : public utils::BasicException {
using utils::BasicException::BasicException;
};
/// Thrown on concurrent index creation when the transaction engine fails to
/// start a new transaction.
class IndexTransactionException : public utils::BasicException {
using utils::BasicException::BasicException;
};
} // namespace database

View File

@ -255,9 +255,9 @@ GraphDbAccessor::ListUniqueLabelPropertyConstraints() const {
return db_.storage().unique_label_property_constraints_.ListConstraints(); return db_.storage().unique_label_property_constraints_.ListConstraints();
} }
void GraphDbAccessor::UpdateLabelIndices(storage::Label label, void GraphDbAccessor::UpdateOnAddLabel(storage::Label label,
const VertexAccessor &vertex_accessor, const VertexAccessor &vertex_accessor,
const Vertex *vertex) { const Vertex *vertex) {
DCHECK(!commited_ && !aborted_) << "Accessor committed or aborted"; DCHECK(!commited_ && !aborted_) << "Accessor committed or aborted";
auto *vlist_ptr = vertex_accessor.address(); auto *vlist_ptr = vertex_accessor.address();
@ -284,7 +284,7 @@ void GraphDbAccessor::UpdateOnRemoveLabel(
label, accessor, transaction()); label, accessor, transaction());
} }
void GraphDbAccessor::UpdatePropertyIndex( void GraphDbAccessor::UpdateOnAddProperty(
storage::Property property, const PropertyValue &value, storage::Property property, const PropertyValue &value,
const RecordAccessor<Vertex> &vertex_accessor, const Vertex *vertex) { const RecordAccessor<Vertex> &vertex_accessor, const Vertex *vertex) {
DCHECK(!commited_ && !aborted_) << "Accessor committed or aborted"; DCHECK(!commited_ && !aborted_) << "Accessor committed or aborted";
@ -299,9 +299,9 @@ void GraphDbAccessor::UpdatePropertyIndex(
} }
} }
void GraphDbAccessor::UpdateOnPropertyRemove( void GraphDbAccessor::UpdateOnRemoveProperty(
storage::Property property, const Vertex *vertex, storage::Property property, const RecordAccessor<Vertex> &accessor,
const RecordAccessor<Vertex> &accessor) { const Vertex *vertex) {
db_.storage().unique_label_property_constraints_.UpdateOnRemoveProperty( db_.storage().unique_label_property_constraints_.UpdateOnRemoveProperty(
property, accessor, transaction()); property, accessor, transaction());
@ -316,7 +316,7 @@ void GraphDbAccessor::BuildExistenceConstraint(
storage::Label label, const std::vector<storage::Property> &properties) { storage::Label label, const std::vector<storage::Property> &properties) {
auto dba = auto dba =
db_.AccessBlocking(std::experimental::make_optional(transaction().id_)); db_.AccessBlocking(std::experimental::make_optional(transaction().id_));
ExistenceRule rule{label, properties}; storage::constraints::ExistenceRule rule{label, properties};
for (auto v : dba->Vertices(false)) { for (auto v : dba->Vertices(false)) {
if (!CheckIfSatisfiesExistenceRule(v.GetOld(), rule)) { if (!CheckIfSatisfiesExistenceRule(v.GetOld(), rule)) {
@ -326,7 +326,10 @@ void GraphDbAccessor::BuildExistenceConstraint(
} }
} }
if (!db_.storage().existence_constraints_.AddConstraint(rule)) return; if (!db_.storage().existence_constraints_.AddConstraint(rule)) {
// Already exists
return;
}
std::vector<std::string> property_names(properties.size()); std::vector<std::string> property_names(properties.size());
std::transform(properties.begin(), properties.end(), property_names.begin(), std::transform(properties.begin(), properties.end(), property_names.begin(),
@ -342,8 +345,11 @@ void GraphDbAccessor::DeleteExistenceConstraint(
storage::Label label, const std::vector<storage::Property> &properties) { storage::Label label, const std::vector<storage::Property> &properties) {
auto dba = auto dba =
db_.AccessBlocking(std::experimental::make_optional(transaction().id_)); db_.AccessBlocking(std::experimental::make_optional(transaction().id_));
ExistenceRule rule{label, properties}; storage::constraints::ExistenceRule rule{label, properties};
if (!db_.storage().existence_constraints_.RemoveConstraint(rule)) return; if (!db_.storage().existence_constraints_.RemoveConstraint(rule)) {
// Nothing was deleted
return;
}
std::vector<std::string> property_names(properties.size()); std::vector<std::string> property_names(properties.size());
std::transform(properties.begin(), properties.end(), property_names.begin(), std::transform(properties.begin(), properties.end(), property_names.begin(),
@ -358,12 +364,12 @@ void GraphDbAccessor::DeleteExistenceConstraint(
bool GraphDbAccessor::ExistenceConstraintExists( bool GraphDbAccessor::ExistenceConstraintExists(
storage::Label label, storage::Label label,
const std::vector<storage::Property> &properties) const { const std::vector<storage::Property> &properties) const {
ExistenceRule rule{label, properties}; storage::constraints::ExistenceRule rule{label, properties};
return db_.storage().existence_constraints_.Exists(rule); return db_.storage().existence_constraints_.Exists(rule);
} }
std::vector<ExistenceRule> GraphDbAccessor::ExistenceConstraintsList() std::vector<storage::constraints::ExistenceRule>
const { GraphDbAccessor::ListExistenceConstraints() const {
return db_.storage().existence_constraints_.ListConstraints(); return db_.storage().existence_constraints_.ListConstraints();
} }

View File

@ -11,6 +11,7 @@
#include <cppitertools/filter.hpp> #include <cppitertools/filter.hpp>
#include <cppitertools/imap.hpp> #include <cppitertools/imap.hpp>
#include "database/single_node/exceptions.hpp"
#include "database/single_node/graph_db.hpp" #include "database/single_node/graph_db.hpp"
#include "storage/common/types/types.hpp" #include "storage/common/types/types.hpp"
#include "storage/single_node/constraints/exceptions.hpp" #include "storage/single_node/constraints/exceptions.hpp"
@ -19,26 +20,8 @@
#include "transactions/transaction.hpp" #include "transactions/transaction.hpp"
#include "transactions/type.hpp" #include "transactions/type.hpp"
#include "utils/bound.hpp" #include "utils/bound.hpp"
#include "utils/exceptions.hpp"
namespace database { namespace database {
/** Thrown when creating an index which already exists. */
class IndexExistsException : public utils::BasicException {
using utils::BasicException::BasicException;
};
/** Thrown when creating an index which already exists. */
class IndexCreationOnWorkerException : public utils::BasicException {
using utils::BasicException::BasicException;
};
/// Thrown on concurrent index creation when the transaction engine fails to
/// start a new transaction.
class IndexTransactionException : public utils::BasicException {
using utils::BasicException::BasicException;
};
/** /**
* Base accessor for the database object: exposes functions for operating on the * Base accessor for the database object: exposes functions for operating on the
* database. All the functions in this class should be self-sufficient: for * database. All the functions in this class should be self-sufficient: for
@ -514,7 +497,8 @@ class GraphDbAccessor {
/** /**
* Returns the list of existence constraints currently active. * Returns the list of existence constraints currently active.
*/ */
std::vector<ExistenceRule> ExistenceConstraintsList() const; std::vector<storage::constraints::ExistenceRule> ListExistenceConstraints()
const;
/** /**
* Return approximate number of all vertices in the database. * Return approximate number of all vertices in the database.
@ -664,18 +648,6 @@ class GraphDbAccessor {
**/ **/
std::vector<std::pair<std::string, std::string>> StorageInfo() const; std::vector<std::pair<std::string, std::string>> StorageInfo() const;
/**
* Insert this vertex into corresponding label and label+property (if it
* exists) index.
*
* @param label - label with which to insert vertex label record
* @param vertex_accessor - vertex_accessor to insert
* @param vertex - vertex record to insert
*/
void UpdateLabelIndices(storage::Label label,
const VertexAccessor &vertex_accessor,
const Vertex *const vertex);
private: private:
GraphDb &db_; GraphDb &db_;
tx::Transaction &transaction_; tx::Transaction &transaction_;
@ -687,29 +659,46 @@ class GraphDbAccessor {
bool aborted_{false}; bool aborted_{false};
/** /**
* Notifies storage about change. * Notifies storage about a change.
*
* @param label - label that was added
* @param vertex_accessor - vertex_accessor that was updated
* @param vertex - vertex that was updated
*/ */
void UpdateOnRemoveLabel(storage::Label label, void UpdateOnAddLabel(storage::Label label,
const VertexAccessor &vertex_accessor,
const Vertex *vertex);
/**
* Notifies storage about a change.
*
* @param label - label that was removed
* @param vertex_accessor - vertex_accessor that was updated
*/
void UpdateOnRemoveLabel(storage::Label label,
const RecordAccessor<Vertex> &accessor); const RecordAccessor<Vertex> &accessor);
/** /**
* Notifies storage about change. * Notifies storage about a change.
* @param vertex_accessor - vertex_accessor that was updated
* @param vertex - vertex that was updated
*/ */
void UpdateOnPropertyRemove(storage::Property property, void UpdateOnRemoveProperty(storage::Property property,
const Vertex *vertex, const RecordAccessor<Vertex> &accessor,
const RecordAccessor<Vertex> &accessor); const Vertex* vertex);
/** /**
* Insert this vertex into corresponding any label + 'property' index. * Notifies storage about a change.
* @param property - vertex will be inserted into indexes which contain this *
* property * @param property - property that was added
* @param vertex_accessor - vertex accessor to insert * @param value - corresponding value that was added
* @param vertex - vertex to insert * @param vertex_accessor - vertex accessor that was updated
* @param vertex - vertex that was updated
*/ */
void UpdatePropertyIndex(storage::Property property, void UpdateOnAddProperty(storage::Property property,
const PropertyValue &value, const PropertyValue &value,
const RecordAccessor<Vertex> &vertex_accessor, const RecordAccessor<Vertex> &vertex_accessor,
const Vertex *const vertex); const Vertex *vertex);
}; };
} // namespace database } // namespace database

View File

@ -58,7 +58,7 @@ bool Encode(const fs::path &snapshot_file, database::GraphDb &db,
// Write existence constraints to snapshoot // Write existence constraints to snapshoot
{ {
std::vector<communication::bolt::Value> existence_constraints; std::vector<communication::bolt::Value> existence_constraints;
for (const auto &rule : dba.ExistenceConstraintsList()) { for (const auto &rule : dba.ListExistenceConstraints()) {
existence_constraints.emplace_back(dba.LabelName(rule.label)); existence_constraints.emplace_back(dba.LabelName(rule.label));
existence_constraints.emplace_back( existence_constraints.emplace_back(
static_cast<int64_t>(rule.properties.size())); static_cast<int64_t>(rule.properties.size()));

View File

@ -1,6 +1,6 @@
#include "storage/single_node/constraints/existence_constraints.hpp" #include "storage/single_node/constraints/existence_constraints.hpp"
namespace database { namespace storage::constraints {
bool Contains(const PropertyValueStore &store, bool Contains(const PropertyValueStore &store,
const std::vector<storage::Property> &properties) { const std::vector<storage::Property> &properties) {
for (auto &property : properties) { for (auto &property : properties) {
@ -13,7 +13,7 @@ bool Contains(const PropertyValueStore &store,
} }
bool CheckIfSatisfiesExistenceRule(const Vertex *vertex, bool CheckIfSatisfiesExistenceRule(const Vertex *vertex,
const database::ExistenceRule &rule) { const ExistenceRule &rule) {
if (!utils::Contains(vertex->labels_, rule.label)) return true; if (!utils::Contains(vertex->labels_, rule.label)) return true;
if (!Contains(vertex->properties_, rule.properties)) return false; if (!Contains(vertex->properties_, rule.properties)) return false;
@ -69,4 +69,4 @@ bool ExistenceConstraints::CheckOnRemoveProperty(
const std::vector<ExistenceRule> &ExistenceConstraints::ListConstraints() const { const std::vector<ExistenceRule> &ExistenceConstraints::ListConstraints() const {
return constraints_; return constraints_;
} }
} // namespace database } // namespace storage::constraints

View File

@ -10,7 +10,7 @@
#include "storage/single_node/vertex.hpp" #include "storage/single_node/vertex.hpp"
#include "transactions/type.hpp" #include "transactions/type.hpp"
namespace database { namespace storage::constraints {
/// Existence rule defines label -> set of properties rule. This means that /// Existence rule defines label -> set of properties rule. This means that
/// every vertex with that label has to have every property in the set of /// every vertex with that label has to have every property in the set of
@ -30,7 +30,7 @@ struct ExistenceRule {
}; };
bool CheckIfSatisfiesExistenceRule(const Vertex *vertex, bool CheckIfSatisfiesExistenceRule(const Vertex *vertex,
const database::ExistenceRule &rule); const ExistenceRule &rule);
/// ExistenceConstraints contains all active constrains. Existence constraints /// ExistenceConstraints contains all active constrains. Existence constraints
/// are restriction on the vertices and are defined by ExistenceRule. /// are restriction on the vertices and are defined by ExistenceRule.
@ -84,4 +84,4 @@ class ExistenceConstraints {
private: private:
std::vector<ExistenceRule> constraints_; std::vector<ExistenceRule> constraints_;
}; };
}; // namespace database }; // namespace storage::constraints

View File

@ -26,7 +26,7 @@ void RecordAccessor<Vertex>::PropsSet(storage::Property key,
auto delta = StateDelta::PropsSetVertex(dba.transaction_id(), gid(), key, auto delta = StateDelta::PropsSetVertex(dba.transaction_id(), gid(), key,
dba.PropertyName(key), value); dba.PropertyName(key), value);
update().properties_.set(key, value); update().properties_.set(key, value);
dba.UpdatePropertyIndex(key, value, *this, &update()); dba.UpdateOnAddProperty(key, value, *this, &update());
db_accessor().wal().Emplace(delta); db_accessor().wal().Emplace(delta);
} }
@ -48,7 +48,7 @@ void RecordAccessor<Vertex>::PropsErase(storage::Property key) {
StateDelta::PropsSetVertex(dba.transaction_id(), gid(), key, StateDelta::PropsSetVertex(dba.transaction_id(), gid(), key,
dba.PropertyName(key), PropertyValue::Null); dba.PropertyName(key), PropertyValue::Null);
update().properties_.set(key, PropertyValue::Null); update().properties_.set(key, PropertyValue::Null);
dba.UpdateOnPropertyRemove(key, GetNew(), *this); dba.UpdateOnRemoveProperty(key, *this, GetNew());
dba.wal().Emplace(delta); dba.wal().Emplace(delta);
} }

View File

@ -78,7 +78,7 @@ class Storage {
LabelPropertyIndex label_property_index_; LabelPropertyIndex label_property_index_;
// existence constraints // existence constraints
ExistenceConstraints existence_constraints_; storage::constraints::ExistenceConstraints existence_constraints_;
// unique constraints // unique constraints
storage::constraints::UniqueLabelPropertyConstraint storage::constraints::UniqueLabelPropertyConstraint

View File

@ -25,7 +25,7 @@ void VertexAccessor::add_label(storage::Label label) {
if (!utils::Contains(vertex.labels_, label)) { if (!utils::Contains(vertex.labels_, label)) {
vertex.labels_.emplace_back(label); vertex.labels_.emplace_back(label);
dba.wal().Emplace(delta); dba.wal().Emplace(delta);
dba.UpdateLabelIndices(label, *this, &vertex); dba.UpdateOnAddLabel(label, *this, &vertex);
} }
} }
@ -40,6 +40,7 @@ void VertexAccessor::remove_label(storage::Label label) {
std::swap(*found, labels.back()); std::swap(*found, labels.back());
labels.pop_back(); labels.pop_back();
dba.wal().Emplace(delta); dba.wal().Emplace(delta);
dba.UpdateOnRemoveLabel(label, *this);
} }
} }

View File

@ -168,8 +168,8 @@ class DbGenerator {
bool CompareExistenceConstraints(const database::GraphDbAccessor &dba1, bool CompareExistenceConstraints(const database::GraphDbAccessor &dba1,
const database::GraphDbAccessor &dba2) { const database::GraphDbAccessor &dba2) {
auto c1 = dba1.ExistenceConstraintsList(); auto c1 = dba1.ListExistenceConstraints();
auto c2 = dba2.ExistenceConstraintsList(); auto c2 = dba2.ListExistenceConstraints();
auto compare_prop = [](auto &dba1, auto &p1, auto &dba2, auto &p2) { auto compare_prop = [](auto &dba1, auto &p1, auto &dba2, auto &p2) {
std::vector<std::string> p1_names; std::vector<std::string> p1_names;

View File

@ -4,131 +4,132 @@
#include "database/single_node/graph_db.hpp" #include "database/single_node/graph_db.hpp"
#include "database/single_node/graph_db_accessor.hpp" #include "database/single_node/graph_db_accessor.hpp"
#include "storage/single_node/constraints/existence_constraints.hpp"
class ExistenceConstraintsTest : public ::testing::Test { class ExistenceConstraintsTest : public ::testing::Test {
public: public:
void SetUp() override {} void SetUp() override {
database::ExistenceConstraints constraints_; auto dba = db_.Access();
label_ = dba->Label("label");
property_ = dba->Property("property");
properties_ = {property_};
rule_ = {label_, properties_};
dba->Commit();
}
storage::constraints::ExistenceConstraints constraints_;
database::GraphDb db_; database::GraphDb db_;
storage::Label label_;
storage::Property property_;
std::vector<storage::Property> properties_;
storage::constraints::ExistenceRule rule_;
}; };
TEST_F(ExistenceConstraintsTest, MultiBuildDrop) { TEST_F(ExistenceConstraintsTest, BuildDrop) {
auto d = db_.Access();
auto label = d->Label("label");
auto prop = d->Property("property");
database::ExistenceRule rule{label, std::vector<storage::Property>{prop}};
d->Commit();
{ {
auto dba = db_.AccessBlocking(); auto dba = db_.Access();
constraints_.AddConstraint(rule); EXPECT_FALSE(dba->ExistenceConstraintExists(label_, properties_));
EXPECT_TRUE(constraints_.Exists(rule));
dba->Commit(); dba->Commit();
} }
{ {
auto dba = db_.AccessBlocking(); auto dba = db_.Access();
constraints_.RemoveConstraint(rule); dba->BuildExistenceConstraint(label_, properties_);
EXPECT_FALSE(constraints_.Exists(rule)); EXPECT_TRUE(dba->ExistenceConstraintExists(label_, properties_));
dba->Commit();
}
{
auto dba = db_.Access();
dba->DeleteExistenceConstraint(label_, properties_);
EXPECT_FALSE(dba->ExistenceConstraintExists(label_, properties_));
dba->Commit(); dba->Commit();
} }
} }
TEST_F(ExistenceConstraintsTest, InsertTest) { TEST_F(ExistenceConstraintsTest, BuildWithViolation) {
auto d = db_.Access();
auto label = d->Label("label");
auto prop = d->Property("property");
database::ExistenceRule rule{label, std::vector<storage::Property>{prop}};
d->Commit();
{ {
auto dba = db_.Access(); auto dba = db_.Access();
auto v = dba->InsertVertex(); auto v = dba->InsertVertex();
v.add_label(label); v.add_label(label_);
EXPECT_TRUE(constraints_.CheckOnAddLabel(v.GetNew(), label));
dba->Commit(); dba->Commit();
} }
{ {
auto dba = db_.Access(); auto dba = db_.Access();
bool can_add_constraint = true; EXPECT_THROW(dba->BuildExistenceConstraint(label_, properties_),
for (auto v : dba->Vertices(false)) { database::IndexConstraintViolationException);
if (!database::CheckIfSatisfiesExistenceRule(v.GetOld(), rule)) { }
can_add_constraint = false; }
}
}
EXPECT_FALSE(can_add_constraint); TEST_F(ExistenceConstraintsTest, InsertFail) {
dba->Commit();
}
{
auto dba = db_.AccessBlocking();
constraints_.AddConstraint(rule);
dba->Commit();
}
{ {
auto dba = db_.Access(); auto dba = db_.Access();
auto v1 = dba->InsertVertex(); dba->BuildExistenceConstraint(label_, properties_);
v1.add_label(label);
EXPECT_FALSE(
constraints_.CheckOnAddLabel(v1.GetNew(), label));
auto v2 = dba->InsertVertex();
v2.PropsSet(prop, PropertyValue(false));
v2.add_label(label);
EXPECT_TRUE(constraints_.CheckOnAddLabel(v2.GetNew(), label));
dba->Commit();
}
{
auto dba = db_.AccessBlocking();
constraints_.RemoveConstraint(rule);
dba->Commit(); dba->Commit();
} }
{ {
auto dba = db_.Access(); auto dba = db_.Access();
auto v = dba->InsertVertex(); auto v = dba->InsertVertex();
v.add_label(label); EXPECT_THROW(v.add_label(label_),
EXPECT_TRUE(constraints_.CheckOnAddLabel(v.GetNew(), label)); database::IndexConstraintViolationException);
}
}
TEST_F(ExistenceConstraintsTest, InsertPass) {
{
auto dba = db_.Access();
dba->BuildExistenceConstraint(label_, properties_);
dba->Commit();
}
{
auto dba = db_.Access();
auto v = dba->InsertVertex();
v.PropsSet(property_, PropertyValue("Something"));
v.add_label(label_);
dba->Commit(); dba->Commit();
} }
} }
TEST_F(ExistenceConstraintsTest, GraphDbAccessor) { TEST_F(ExistenceConstraintsTest, RemoveFail) {
auto d = db_.Access(); {
auto label = d->Label("label"); auto dba = db_.Access();
auto prop = d->Property("property"); dba->BuildExistenceConstraint(label_, properties_);
auto properties = std::vector<storage::Property>{prop}; dba->Commit();
d->Commit(); }
gid::Gid gid;
{
auto dba = db_.Access();
auto v = dba->InsertVertex();
v.PropsSet(property_, PropertyValue("Something"));
v.add_label(label_);
gid = v.gid();
dba->Commit();
}
{
auto dba = db_.Access();
auto v = dba->FindVertex(gid, false);
EXPECT_THROW(v.PropsErase(property_),
database::IndexConstraintViolationException);
}
}
TEST_F(ExistenceConstraintsTest, RemovePass) {
{ {
auto dba = db_.Access(); auto dba = db_.Access();
dba->BuildExistenceConstraint(label, properties); dba->BuildExistenceConstraint(label_, properties_);
// Constraint is not visible because transaction creates blocking dba->Commit();
// transaction with different id; }
gid::Gid gid;
{
auto dba = db_.Access();
auto v = dba->InsertVertex();
v.PropsSet(property_, PropertyValue("Something"));
v.add_label(label_);
gid = v.gid();
dba->Commit(); dba->Commit();
} }
{ {
auto dba = db_.Access(); auto dba = db_.Access();
EXPECT_TRUE(dba->ExistenceConstraintExists(label, properties)); auto v = dba->FindVertex(gid, false);
auto v1 = dba->InsertVertex(); v.remove_label(label_);
EXPECT_THROW(v1.add_label(label), v.PropsErase(property_);
database::IndexConstraintViolationException);
auto v2 = dba->InsertVertex();
v2.PropsSet(prop, PropertyValue(false));
v2.add_label(label);
EXPECT_THROW(v2.PropsErase(prop),
database::IndexConstraintViolationException);
v2.remove_label(label);
dba->Commit();
}
{
auto dba = db_.Access();
dba->DeleteExistenceConstraint(label, properties);
dba->Commit();
}
{
auto dba = db_.Access();
EXPECT_FALSE(dba->ExistenceConstraintExists(label, properties));
auto v1 = dba->InsertVertex();
v1.add_label(label);
dba->Commit(); dba->Commit();
} }
} }

View File

@ -4,15 +4,14 @@
#include "database/single_node/graph_db.hpp" #include "database/single_node/graph_db.hpp"
#include "database/single_node/graph_db_accessor.hpp" #include "database/single_node/graph_db_accessor.hpp"
#include "storage/single_node/constraints/unique_label_property_constraint.hpp"
class UniqueLabelPropertyTest : public ::testing::Test { class UniqueLabelPropertyTest : public ::testing::Test {
public: public:
void SetUp() override { void SetUp() override {
auto dba = db_.AccessBlocking(); auto dba = db_.Access();
label_ = dba->Label("label"); label_ = dba->Label("label");
property_ = dba->Property("property"); property_ = dba->Property("property");
constraint_.AddConstraint(label_, property_, dba->transaction()); dba->BuildUniqueConstraint(label_, property_);
dba->Commit(); dba->Commit();
} }
@ -20,43 +19,42 @@ class UniqueLabelPropertyTest : public ::testing::Test {
storage::Label label_; storage::Label label_;
storage::Property property_; storage::Property property_;
PropertyValue value_{"value"}; PropertyValue value_{"value"};
storage::constraints::UniqueLabelPropertyConstraint constraint_;
}; };
TEST_F(UniqueLabelPropertyTest, BuildDrop) { TEST_F(UniqueLabelPropertyTest, BuildDrop) {
{ {
auto dba = db_.Access(); auto dba = db_.Access();
EXPECT_TRUE(constraint_.Exists(label_, property_)); EXPECT_TRUE(dba->UniqueConstraintExists(label_, property_));
dba->Commit(); dba->Commit();
} }
{ {
auto dba = db_.Access(); auto dba = db_.Access();
constraint_.RemoveConstraint(label_, property_); dba->DeleteUniqueConstraint(label_, property_);
dba->Commit(); dba->Commit();
} }
{ {
auto dba = db_.Access(); auto dba = db_.Access();
EXPECT_FALSE(constraint_.Exists(label_, property_)); EXPECT_FALSE(dba->UniqueConstraintExists(label_, property_));
dba->Commit(); dba->Commit();
} }
} }
TEST_F(UniqueLabelPropertyTest, BuildWithViolation) { TEST_F(UniqueLabelPropertyTest, BuildWithViolation) {
auto dba1 = db_.Access(); auto dba1 = db_.Access();
auto l1 = dba1->Label("l1");
auto p1 = dba1->Property("p1");
auto v1 = dba1->InsertVertex(); auto v1 = dba1->InsertVertex();
v1.add_label(label_); v1.add_label(l1);
v1.PropsSet(property_, value_); v1.PropsSet(p1, value_);
auto v2 = dba1->InsertVertex(); auto v2 = dba1->InsertVertex();
v2.add_label(label_); v2.add_label(l1);
v2.PropsSet(property_, value_); v2.PropsSet(p1, value_);
dba1->Commit(); dba1->Commit();
auto dba2 = db_.Access(); auto dba2 = db_.Access();
auto v3 = dba2->FindVertex(v1.gid(), false); EXPECT_THROW(dba2->BuildUniqueConstraint(l1, p1),
auto v4 = dba2->FindVertex(v2.gid(), false);
constraint_.Update(v3, dba2->transaction());
EXPECT_THROW(constraint_.Update(v4, dba2->transaction()),
database::IndexConstraintViolationException); database::IndexConstraintViolationException);
} }
@ -65,23 +63,15 @@ TEST_F(UniqueLabelPropertyTest, InsertInsert) {
auto dba = db_.Access(); auto dba = db_.Access();
auto v = dba->InsertVertex(); auto v = dba->InsertVertex();
v.add_label(label_); v.add_label(label_);
constraint_.UpdateOnAddLabel(label_, v, dba->transaction());
v.PropsSet(property_, value_); v.PropsSet(property_, value_);
constraint_.UpdateOnAddProperty(property_, value_, v, dba->transaction());
dba->Commit(); dba->Commit();
} }
{ {
auto dba = db_.Access(); auto dba = db_.Access();
auto v = dba->InsertVertex(); auto v = dba->InsertVertex();
v.add_label(label_); v.add_label(label_);
constraint_.UpdateOnAddLabel(label_, v, dba->transaction()); EXPECT_THROW(v.PropsSet(property_, value_),
v.PropsSet(property_, value_); database::IndexConstraintViolationException);
EXPECT_THROW(constraint_.UpdateOnAddProperty(property_, value_, v,
dba->transaction()),
database::IndexConstraintViolationException);
EXPECT_THROW(constraint_.UpdateOnAddLabel(label_, v, dba->transaction()),
database::IndexConstraintViolationException);
dba->Commit();
} }
} }
@ -90,9 +80,7 @@ TEST_F(UniqueLabelPropertyTest, InsertInsertDiffValues) {
auto dba = db_.Access(); auto dba = db_.Access();
auto v = dba->InsertVertex(); auto v = dba->InsertVertex();
v.add_label(label_); v.add_label(label_);
constraint_.UpdateOnAddLabel(label_, v, dba->transaction());
v.PropsSet(property_, value_); v.PropsSet(property_, value_);
constraint_.UpdateOnAddProperty(property_, value_, v, dba->transaction());
dba->Commit(); dba->Commit();
} }
{ {
@ -100,10 +88,7 @@ TEST_F(UniqueLabelPropertyTest, InsertInsertDiffValues) {
auto v = dba->InsertVertex(); auto v = dba->InsertVertex();
PropertyValue other_value{"Some other value"}; PropertyValue other_value{"Some other value"};
v.add_label(label_); v.add_label(label_);
constraint_.UpdateOnAddLabel(label_, v, dba->transaction());
v.PropsSet(property_, other_value); v.PropsSet(property_, other_value);
constraint_.UpdateOnAddProperty(property_, other_value, v,
dba->transaction());
dba->Commit(); dba->Commit();
} }
} }
@ -113,18 +98,14 @@ TEST_F(UniqueLabelPropertyTest, InsertAbortInsert) {
auto dba = db_.Access(); auto dba = db_.Access();
auto v = dba->InsertVertex(); auto v = dba->InsertVertex();
v.add_label(label_); v.add_label(label_);
constraint_.UpdateOnAddLabel(label_, v, dba->transaction());
v.PropsSet(property_, value_); v.PropsSet(property_, value_);
constraint_.UpdateOnAddProperty(property_, value_, v, dba->transaction());
dba->Abort(); dba->Abort();
} }
{ {
auto dba = db_.Access(); auto dba = db_.Access();
auto v = dba->InsertVertex(); auto v = dba->InsertVertex();
v.add_label(label_); v.add_label(label_);
constraint_.UpdateOnAddLabel(label_, v, dba->transaction());
v.PropsSet(property_, value_); v.PropsSet(property_, value_);
constraint_.UpdateOnAddProperty(property_, value_, v, dba->transaction());
dba->Commit(); dba->Commit();
} }
} }
@ -135,9 +116,7 @@ TEST_F(UniqueLabelPropertyTest, InsertRemoveAbortInsert) {
auto dba = db_.Access(); auto dba = db_.Access();
auto v = dba->InsertVertex(); auto v = dba->InsertVertex();
v.add_label(label_); v.add_label(label_);
constraint_.UpdateOnAddLabel(label_, v, dba->transaction());
v.PropsSet(property_, value_); v.PropsSet(property_, value_);
constraint_.UpdateOnAddProperty(property_, value_, v, dba->transaction());
gid = v.gid(); gid = v.gid();
dba->Commit(); dba->Commit();
} }
@ -145,17 +124,13 @@ TEST_F(UniqueLabelPropertyTest, InsertRemoveAbortInsert) {
auto dba = db_.Access(); auto dba = db_.Access();
auto v = dba->FindVertex(gid, false); auto v = dba->FindVertex(gid, false);
v.PropsErase(property_); v.PropsErase(property_);
constraint_.UpdateOnRemoveProperty(property_, v, dba->transaction());
dba->Abort(); dba->Abort();
} }
{ {
auto dba = db_.Access(); auto dba = db_.Access();
auto v = dba->InsertVertex(); auto v = dba->InsertVertex();
v.add_label(label_); v.add_label(label_);
constraint_.UpdateOnAddLabel(label_, v, dba->transaction()); EXPECT_THROW(v.PropsSet(property_, value_),
v.PropsSet(property_, value_);
EXPECT_THROW(constraint_.UpdateOnAddProperty(property_, value_, v,
dba->transaction()),
database::IndexConstraintViolationException); database::IndexConstraintViolationException);
} }
} }
@ -165,16 +140,11 @@ TEST_F(UniqueLabelPropertyTest, InsertInsertSameTransaction) {
auto dba = db_.Access(); auto dba = db_.Access();
auto v1 = dba->InsertVertex(); auto v1 = dba->InsertVertex();
v1.add_label(label_); v1.add_label(label_);
constraint_.UpdateOnAddLabel(label_, v1, dba->transaction());
v1.PropsSet(property_, value_); v1.PropsSet(property_, value_);
constraint_.UpdateOnAddProperty(property_, value_, v1, dba->transaction());
auto v2 = dba->InsertVertex(); auto v2 = dba->InsertVertex();
v2.add_label(label_); v2.add_label(label_);
constraint_.UpdateOnAddLabel(label_, v2, dba->transaction()); EXPECT_THROW(v2.PropsSet(property_, value_),
v2.PropsSet(property_, value_);
EXPECT_THROW(constraint_.UpdateOnAddProperty(property_, value_, v2,
dba->transaction()),
database::IndexConstraintViolationException); database::IndexConstraintViolationException);
} }
} }
@ -185,17 +155,12 @@ TEST_F(UniqueLabelPropertyTest, InsertInsertReversed) {
auto v2 = dba2->InsertVertex(); auto v2 = dba2->InsertVertex();
v2.add_label(label_); v2.add_label(label_);
constraint_.UpdateOnAddLabel(label_, v2, dba2->transaction());
v2.PropsSet(property_, value_); v2.PropsSet(property_, value_);
constraint_.UpdateOnAddProperty(property_, value_, v2, dba2->transaction());
dba2->Commit(); dba2->Commit();
auto v1 = dba1->InsertVertex(); auto v1 = dba1->InsertVertex();
v1.add_label(label_); v1.add_label(label_);
constraint_.UpdateOnAddLabel(label_, v1, dba1->transaction()); EXPECT_THROW(v1.PropsSet(property_, value_),
v1.PropsSet(property_, value_);
EXPECT_THROW(constraint_.UpdateOnAddProperty(property_, value_, v1,
dba1->transaction()),
mvcc::SerializationError); mvcc::SerializationError);
} }
@ -205,9 +170,7 @@ TEST_F(UniqueLabelPropertyTest, InsertRemoveInsert) {
auto dba = db_.Access(); auto dba = db_.Access();
auto v = dba->InsertVertex(); auto v = dba->InsertVertex();
v.add_label(label_); v.add_label(label_);
constraint_.UpdateOnAddLabel(label_, v, dba->transaction());
v.PropsSet(property_, value_); v.PropsSet(property_, value_);
constraint_.UpdateOnAddProperty(property_, value_, v, dba->transaction());
gid = v.gid(); gid = v.gid();
dba->Commit(); dba->Commit();
} }
@ -215,16 +178,13 @@ TEST_F(UniqueLabelPropertyTest, InsertRemoveInsert) {
auto dba = db_.Access(); auto dba = db_.Access();
auto v = dba->FindVertex(gid, false); auto v = dba->FindVertex(gid, false);
v.PropsErase(property_); v.PropsErase(property_);
constraint_.UpdateOnRemoveProperty(property_, v, dba->transaction());
dba->Commit(); dba->Commit();
} }
{ {
auto dba = db_.Access(); auto dba = db_.Access();
auto v = dba->InsertVertex(); auto v = dba->InsertVertex();
v.add_label(label_); v.add_label(label_);
constraint_.UpdateOnAddLabel(label_, v, dba->transaction());
v.PropsSet(property_, value_); v.PropsSet(property_, value_);
constraint_.UpdateOnAddProperty(property_, value_, v, dba->transaction());
} }
} }
@ -232,13 +192,9 @@ TEST_F(UniqueLabelPropertyTest, InsertRemoveInsertSameTransaction) {
auto dba = db_.Access(); auto dba = db_.Access();
auto v = dba->InsertVertex(); auto v = dba->InsertVertex();
v.add_label(label_); v.add_label(label_);
constraint_.UpdateOnAddLabel(label_, v, dba->transaction());
v.PropsSet(property_, value_); v.PropsSet(property_, value_);
constraint_.UpdateOnAddProperty(property_, value_, v, dba->transaction());
v.PropsErase(property_); v.PropsErase(property_);
constraint_.UpdateOnRemoveProperty(property_, v, dba->transaction());
v.PropsSet(property_, value_); v.PropsSet(property_, value_);
constraint_.UpdateOnAddProperty(property_, value_, v, dba->transaction());
dba->Commit(); dba->Commit();
} }
@ -247,23 +203,19 @@ TEST_F(UniqueLabelPropertyTest, InsertDropInsert) {
auto dba = db_.Access(); auto dba = db_.Access();
auto v = dba->InsertVertex(); auto v = dba->InsertVertex();
v.add_label(label_); v.add_label(label_);
constraint_.UpdateOnAddLabel(label_, v, dba->transaction());
v.PropsSet(property_, value_); v.PropsSet(property_, value_);
constraint_.UpdateOnAddProperty(property_, value_, v, dba->transaction());
dba->Commit(); dba->Commit();
} }
{ {
auto dba = db_.AccessBlocking(); auto dba = db_.Access();
constraint_.RemoveConstraint(label_, property_); dba->DeleteUniqueConstraint(label_, property_);
dba->Commit(); dba->Commit();
} }
{ {
auto dba = db_.Access(); auto dba = db_.Access();
auto v = dba->InsertVertex(); auto v = dba->InsertVertex();
v.add_label(label_); v.add_label(label_);
constraint_.UpdateOnAddLabel(label_, v, dba->transaction());
v.PropsSet(property_, value_); v.PropsSet(property_, value_);
constraint_.UpdateOnAddProperty(property_, value_, v, dba->transaction());
dba->Commit(); dba->Commit();
} }
} }