Add support for dumping unqiue constraints

Summary: Dumps unique constraints, tests included

Reviewers: teon.banek, msantl

Reviewed By: msantl

Subscribers: pullbot

Differential Revision: https://phabricator.memgraph.io/D2112
This commit is contained in:
Tonko Sabolcec 2019-06-10 13:55:11 +02:00
parent 8194fbd6f7
commit 485592eb48
3 changed files with 84 additions and 4 deletions

View File

@ -119,6 +119,18 @@ void DumpIndexKey(std::ostream *os, GraphDbAccessor *dba,
<< dba->PropertyName(key.property_) << ");";
}
void DumpUniqueConstraint(
std::ostream *os, GraphDbAccessor *dba,
const storage::constraints::ConstraintEntry &constraint) {
*os << "CREATE CONSTRAINT ON (u:" << dba->LabelName(constraint.label)
<< ") ASSERT ";
utils::PrintIterable(*os, constraint.properties, ", ",
[&dba](auto &os, const auto &property) {
os << "u." << dba->PropertyName(property);
});
*os << " IS UNIQUE;";
}
} // namespace
CypherDumpGenerator::CypherDumpGenerator(GraphDbAccessor *dba)
@ -128,6 +140,7 @@ CypherDumpGenerator::CypherDumpGenerator(GraphDbAccessor *dba)
cleaned_internal_label_property_(false) {
CHECK(dba);
indices_state_.emplace(dba->GetIndicesKeys());
unique_constraints_state_.emplace(dba->ListUniqueConstraints());
vertices_state_.emplace(dba->Vertices(false));
edges_state_.emplace(dba->Edges(false));
}
@ -141,6 +154,10 @@ bool CypherDumpGenerator::NextQuery(std::ostream *os) {
<< kInternalPropertyId << ");";
created_internal_index_ = true;
return true;
} else if (!unique_constraints_state_->ReachedEnd()) {
DumpUniqueConstraint(os, dba_,
*unique_constraints_state_->GetCurrentAndAdvance());
return true;
} else if (!vertices_state_->ReachedEnd()) {
DumpVertex(os, dba_, *vertices_state_->GetCurrentAndAdvance());
return true;

View File

@ -3,6 +3,7 @@
#include <ostream>
#include "database/graph_db_accessor.hpp"
#include "storage/common/constraints/unique_constraints.hpp"
namespace database {
@ -73,6 +74,9 @@ class CypherDumpGenerator {
std::optional<ContainerState<std::vector<LabelPropertyIndex::Key>>>
indices_state_;
std::optional<
ContainerState<std::vector<storage::constraints::ConstraintEntry>>>
unique_constraints_state_;
std::optional<ContainerState<decltype(dba_->Vertices(false))>>
vertices_state_;
std::optional<ContainerState<decltype(dba_->Edges(false))>> edges_state_;

View File

@ -46,9 +46,15 @@ struct DatabaseState {
std::string property;
};
struct UniqueConstraint {
std::string label;
std::set<std::string> props;
};
std::set<Vertex> vertices;
std::set<Edge> edges;
std::set<IndexKey> indices;
std::set<UniqueConstraint> constraints;
};
bool operator<(const DatabaseState::Vertex &first,
@ -73,6 +79,12 @@ bool operator<(const DatabaseState::IndexKey &first,
return first.property < second.property;
}
bool operator<(const DatabaseState::UniqueConstraint &first,
const DatabaseState::UniqueConstraint &second) {
if (first.label != second.label) return first.label < second.label;
return first.props < second.props;
}
bool operator==(const DatabaseState::Vertex &first,
const DatabaseState::Vertex &second) {
return first.id == second.id && first.labels == second.labels &&
@ -90,6 +102,11 @@ bool operator==(const DatabaseState::IndexKey &first,
return first.label == second.label && first.property == second.property;
}
bool operator==(const DatabaseState::UniqueConstraint &first,
const DatabaseState::UniqueConstraint &second) {
return first.label == second.label && first.props == second.props;
}
bool operator==(const DatabaseState &first, const DatabaseState &second) {
return first.vertices == second.vertices && first.edges == second.edges &&
first.indices == second.indices;
@ -147,7 +164,17 @@ class DatabaseEnvironment {
{dba.LabelName(key.label_), dba.PropertyName(key.property_)});
}
return {vertices, edges, indices};
// Capture all unique constraints
std::set<DatabaseState::UniqueConstraint> constraints;
for (const auto &constraint : dba.ListUniqueConstraints()) {
std::set<std::string> props;
for (const auto &prop : constraint.properties) {
props.insert(dba.PropertyName(prop));
}
constraints.insert({dba.LabelName(constraint.label), props});
}
return {vertices, edges, indices, constraints};
}
private:
@ -423,6 +450,37 @@ TEST(DumpTest, IndicesKeys) {
}
}
// NOLINTNEXTLINE(hicpp-special-member-functions)
TEST(DumpTest, UniqueConstraints) {
DatabaseEnvironment db;
{
auto dba = db.Access();
CreateVertex(&dba, {"Label"}, {{"prop", 1}}, false);
Execute(&dba, "CREATE CONSTRAINT ON (u:Label) ASSERT u.prop IS UNIQUE;");
// Create one with multiple properties.
Execute(
&dba,
"CREATE CONSTRAINT ON (u:Label) ASSERT u.prop1, u.prop2 IS UNIQUE;");
dba.Commit();
}
{
auto dba = db.Access();
CypherDumpGenerator dump(&dba);
EXPECT_EQ(DumpNext(&dump), kCreateInternalIndex);
EXPECT_EQ(DumpNext(&dump),
"CREATE CONSTRAINT ON (u:Label) ASSERT u.prop IS UNIQUE;");
EXPECT_EQ(
DumpNext(&dump),
"CREATE CONSTRAINT ON (u:Label) ASSERT u.prop1, u.prop2 IS UNIQUE;");
EXPECT_EQ(DumpNext(&dump),
"CREATE (:__mg_vertex__:Label {__mg_id__: 0, prop: 1});");
EXPECT_EQ(DumpNext(&dump), kDropInternalIndex);
EXPECT_EQ(DumpNext(&dump), kRemoveInternalLabelProperty);
EXPECT_EQ(DumpNext(&dump), "");
}
}
// NOLINTNEXTLINE(hicpp-special-member-functions)
TEST(DumpTest, CheckStateVertexWithMultipleProperties) {
DatabaseEnvironment db;
@ -456,8 +514,8 @@ TEST(DumpTest, CheckStateSimpleGraph) {
auto dba = db.Access();
auto u = CreateVertex(&dba, {"Person"}, {{"name", "Ivan"}});
auto v = CreateVertex(&dba, {"Person"}, {{"name", "Josko"}});
auto w = CreateVertex(&dba, {"Person"}, {{"name", "Bosko"}});
auto z = CreateVertex(&dba, {"Person"}, {{"name", "Buha"}});
auto w = CreateVertex(&dba, {"Person"}, {{"name", "Bosko"}, {"id", 0}});
auto z = CreateVertex(&dba, {"Person"}, {{"name", "Buha"}, {"id", 1}});
CreateEdge(&dba, u, v, "Knows", {});
CreateEdge(&dba, v, w, "Knows", {{"how_long", 5}});
CreateEdge(&dba, w, u, "Knows", {{"how", "distant past"}});
@ -467,7 +525,8 @@ TEST(DumpTest, CheckStateSimpleGraph) {
CreateEdge(&dba, w, z, "Knows", {{"how", "school"}});
CreateEdge(&dba, w, z, "Likes", {{"how", "very much"}});
// Create few indices
Execute(&dba, "CREATE INDEX ON :Person(name);");
Execute(&dba, "CREATE CONSTRAINT ON (u:Person) ASSERT u.name IS UNIQUE;");
Execute(&dba, "CREATE INDEX ON :Person(id);");
Execute(&dba, "CREATE INDEX ON :Person(unexisting_property);");
}