Update query dump with unique constraints

Summary:
Now that unique constraint feature is added to Memgraph database,
we should update `DUMP DATABASE` with list of existing unique constraints.

Reviewers: mferencevic

Reviewed By: mferencevic

Subscribers: pullbot

Differential Revision: https://phabricator.memgraph.io/D2698
This commit is contained in:
Tonko Sabolcec 2020-03-02 13:03:43 +01:00
parent b922ca75d0
commit 14c4c6d060
2 changed files with 100 additions and 5 deletions

View File

@ -189,6 +189,17 @@ void DumpExistenceConstraint(std::ostream *os, query::DbAccessor *dba,
<< ") ASSERT EXISTS (u." << dba->PropertyToName(property) << ");";
}
void DumpUniqueConstraint(std::ostream *os, query::DbAccessor *dba,
storage::LabelId label,
const std::set<storage::PropertyId> &properties) {
*os << "CREATE CONSTRAINT ON (u:" << dba->LabelToName(label) << ") ASSERT ";
utils::PrintIterable(*os, properties, ", ",
[&dba](auto &stream, const auto &property) {
stream << "u." << dba->PropertyToName(property);
});
*os << " IS UNIQUE;";
}
} // namespace
void DumpDatabaseToCypherQueries(query::DbAccessor *dba, AnyStream *stream) {
@ -212,6 +223,11 @@ void DumpDatabaseToCypherQueries(query::DbAccessor *dba, AnyStream *stream) {
DumpExistenceConstraint(&os, dba, item.first, item.second);
stream->Result({TypedValue(os.str())});
}
for (const auto &item : info.unique) {
std::ostringstream os;
DumpUniqueConstraint(&os, dba, item.first, item.second);
stream->Result({TypedValue(os.str())});
}
}
auto vertices = dba->Vertices(storage::View::OLD);

View File

@ -45,11 +45,17 @@ struct DatabaseState {
std::string property;
};
struct LabelPropertiesItem {
std::string label;
std::set<std::string> properties;
};
std::set<Vertex> vertices;
std::set<Edge> edges;
std::set<LabelItem> label_indices;
std::set<LabelPropertyItem> label_property_indices;
std::set<LabelPropertyItem> existence_constraints;
std::set<LabelPropertiesItem> unique_constraints;
};
bool operator<(const DatabaseState::Vertex &first,
@ -79,6 +85,12 @@ bool operator<(const DatabaseState::LabelPropertyItem &first,
return first.property < second.property;
}
bool operator<(const DatabaseState::LabelPropertiesItem &first,
const DatabaseState::LabelPropertiesItem &second) {
if (first.label != second.label) return first.label < second.label;
return first.properties < second.properties;
}
bool operator==(const DatabaseState::Vertex &first,
const DatabaseState::Vertex &second) {
return first.id == second.id && first.labels == second.labels &&
@ -101,11 +113,17 @@ bool operator==(const DatabaseState::LabelPropertyItem &first,
return first.label == second.label && first.property == second.property;
}
bool operator==(const DatabaseState::LabelPropertiesItem &first,
const DatabaseState::LabelPropertiesItem &second) {
return first.label == second.label && first.properties == second.properties;
}
bool operator==(const DatabaseState &first, const DatabaseState &second) {
return first.vertices == second.vertices && first.edges == second.edges &&
first.label_indices == second.label_indices &&
first.label_property_indices == second.label_property_indices &&
first.existence_constraints == second.existence_constraints;
first.existence_constraints == second.existence_constraints &&
first.unique_constraints == second.unique_constraints;
}
DatabaseState GetState(storage::Storage *db) {
@ -167,16 +185,29 @@ DatabaseState GetState(storage::Storage *db) {
// Capture all constraints
std::set<DatabaseState::LabelPropertyItem> existence_constraints;
std::set<DatabaseState::LabelPropertiesItem> unique_constraints;
{
auto info = dba.ListAllConstraints();
for (const auto &item : info.existence) {
existence_constraints.insert(
{dba.LabelToName(item.first), dba.PropertyToName(item.second)});
}
for (const auto &item : info.unique) {
std::set<std::string> properties;
for (const auto &property : item.second) {
properties.insert(dba.PropertyToName(property));
}
unique_constraints.insert(
{dba.LabelToName(item.first), std::move(properties)});
}
}
return {vertices, edges, label_indices, label_property_indices,
existence_constraints};
return {vertices,
edges,
label_indices,
label_property_indices,
existence_constraints,
unique_constraints};
}
auto Execute(storage::Storage *db, const std::string &query) {
@ -537,6 +568,47 @@ TEST(DumpTest, ExistenceConstraints) {
}
}
TEST(DumpTest, UniqueConstraints) {
storage::Storage db;
{
auto dba = db.Access();
CreateVertex(&dba, {"Label"},
{{"prop", storage::PropertyValue(1)},
{"prop2", storage::PropertyValue(2)}},
false);
CreateVertex(&dba, {"Label"},
{{"prop", storage::PropertyValue(2)},
{"prop2", storage::PropertyValue(2)}},
false);
ASSERT_FALSE(dba.Commit().HasError());
}
{
auto res = db.CreateUniqueConstraint(
db.NameToLabel("Label"),
{db.NameToProperty("prop"), db.NameToProperty("prop2")});
ASSERT_TRUE(res.HasValue());
ASSERT_EQ(res.GetValue(),
storage::UniqueConstraints::CreationStatus::SUCCESS);
}
{
ResultStreamFaker stream(&db);
query::AnyStream query_stream(&stream, utils::NewDeleteResource());
{
auto acc = db.Access();
query::DbAccessor dba(&acc);
query::DumpDatabaseToCypherQueries(&dba, &query_stream);
}
VerifyQueries(
stream.GetResults(),
"CREATE CONSTRAINT ON (u:Label) ASSERT u.prop, u.prop2 IS UNIQUE;",
kCreateInternalIndex,
"CREATE (:__mg_vertex__:Label {__mg_id__: 0, prop: 1, prop2: 2});",
"CREATE (:__mg_vertex__:Label {__mg_id__: 1, prop: 2, prop2: 2});",
kDropInternalIndex, kRemoveInternalLabelProperty);
}
}
// NOLINTNEXTLINE(hicpp-special-member-functions)
TEST(DumpTest, CheckStateVertexWithMultipleProperties) {
storage::Storage db;
@ -606,6 +678,13 @@ TEST(DumpTest, CheckStateSimpleGraph) {
ASSERT_TRUE(ret.HasValue());
ASSERT_TRUE(ret.GetValue());
}
{
auto ret = db.CreateUniqueConstraint(db.NameToLabel("Person"),
{db.NameToProperty("name")});
ASSERT_TRUE(ret.HasValue());
ASSERT_EQ(ret.GetValue(),
storage::UniqueConstraints::CreationStatus::SUCCESS);
}
ASSERT_TRUE(
db.CreateIndex(db.NameToLabel("Person"), db.NameToProperty("id")));
ASSERT_TRUE(db.CreateIndex(db.NameToLabel("Person"),
@ -622,9 +701,9 @@ TEST(DumpTest, CheckStateSimpleGraph) {
query::DumpDatabaseToCypherQueries(&dba, &query_stream);
}
const auto &results = stream.GetResults();
// Indices and constraints are 3 queries and there must be at least one more
// Indices and constraints are 4 queries and there must be at least one more
// query for the data.
ASSERT_GE(results.size(), 4);
ASSERT_GE(results.size(), 5);
for (const auto &item : results) {
ASSERT_EQ(item.size(), 1);
ASSERT_TRUE(item[0].IsString());