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:
parent
b922ca75d0
commit
14c4c6d060
@ -189,6 +189,17 @@ void DumpExistenceConstraint(std::ostream *os, query::DbAccessor *dba,
|
|||||||
<< ") ASSERT EXISTS (u." << dba->PropertyToName(property) << ");";
|
<< ") 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
|
} // namespace
|
||||||
|
|
||||||
void DumpDatabaseToCypherQueries(query::DbAccessor *dba, AnyStream *stream) {
|
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);
|
DumpExistenceConstraint(&os, dba, item.first, item.second);
|
||||||
stream->Result({TypedValue(os.str())});
|
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);
|
auto vertices = dba->Vertices(storage::View::OLD);
|
||||||
|
@ -45,11 +45,17 @@ struct DatabaseState {
|
|||||||
std::string property;
|
std::string property;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct LabelPropertiesItem {
|
||||||
|
std::string label;
|
||||||
|
std::set<std::string> properties;
|
||||||
|
};
|
||||||
|
|
||||||
std::set<Vertex> vertices;
|
std::set<Vertex> vertices;
|
||||||
std::set<Edge> edges;
|
std::set<Edge> edges;
|
||||||
std::set<LabelItem> label_indices;
|
std::set<LabelItem> label_indices;
|
||||||
std::set<LabelPropertyItem> label_property_indices;
|
std::set<LabelPropertyItem> label_property_indices;
|
||||||
std::set<LabelPropertyItem> existence_constraints;
|
std::set<LabelPropertyItem> existence_constraints;
|
||||||
|
std::set<LabelPropertiesItem> unique_constraints;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool operator<(const DatabaseState::Vertex &first,
|
bool operator<(const DatabaseState::Vertex &first,
|
||||||
@ -79,6 +85,12 @@ bool operator<(const DatabaseState::LabelPropertyItem &first,
|
|||||||
return first.property < second.property;
|
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,
|
bool operator==(const DatabaseState::Vertex &first,
|
||||||
const DatabaseState::Vertex &second) {
|
const DatabaseState::Vertex &second) {
|
||||||
return first.id == second.id && first.labels == second.labels &&
|
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;
|
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) {
|
bool operator==(const DatabaseState &first, const DatabaseState &second) {
|
||||||
return first.vertices == second.vertices && first.edges == second.edges &&
|
return first.vertices == second.vertices && first.edges == second.edges &&
|
||||||
first.label_indices == second.label_indices &&
|
first.label_indices == second.label_indices &&
|
||||||
first.label_property_indices == second.label_property_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) {
|
DatabaseState GetState(storage::Storage *db) {
|
||||||
@ -167,16 +185,29 @@ DatabaseState GetState(storage::Storage *db) {
|
|||||||
|
|
||||||
// Capture all constraints
|
// Capture all constraints
|
||||||
std::set<DatabaseState::LabelPropertyItem> existence_constraints;
|
std::set<DatabaseState::LabelPropertyItem> existence_constraints;
|
||||||
|
std::set<DatabaseState::LabelPropertiesItem> unique_constraints;
|
||||||
{
|
{
|
||||||
auto info = dba.ListAllConstraints();
|
auto info = dba.ListAllConstraints();
|
||||||
for (const auto &item : info.existence) {
|
for (const auto &item : info.existence) {
|
||||||
existence_constraints.insert(
|
existence_constraints.insert(
|
||||||
{dba.LabelToName(item.first), dba.PropertyToName(item.second)});
|
{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,
|
return {vertices,
|
||||||
existence_constraints};
|
edges,
|
||||||
|
label_indices,
|
||||||
|
label_property_indices,
|
||||||
|
existence_constraints,
|
||||||
|
unique_constraints};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Execute(storage::Storage *db, const std::string &query) {
|
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)
|
// NOLINTNEXTLINE(hicpp-special-member-functions)
|
||||||
TEST(DumpTest, CheckStateVertexWithMultipleProperties) {
|
TEST(DumpTest, CheckStateVertexWithMultipleProperties) {
|
||||||
storage::Storage db;
|
storage::Storage db;
|
||||||
@ -606,6 +678,13 @@ TEST(DumpTest, CheckStateSimpleGraph) {
|
|||||||
ASSERT_TRUE(ret.HasValue());
|
ASSERT_TRUE(ret.HasValue());
|
||||||
ASSERT_TRUE(ret.GetValue());
|
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(
|
ASSERT_TRUE(
|
||||||
db.CreateIndex(db.NameToLabel("Person"), db.NameToProperty("id")));
|
db.CreateIndex(db.NameToLabel("Person"), db.NameToProperty("id")));
|
||||||
ASSERT_TRUE(db.CreateIndex(db.NameToLabel("Person"),
|
ASSERT_TRUE(db.CreateIndex(db.NameToLabel("Person"),
|
||||||
@ -622,9 +701,9 @@ TEST(DumpTest, CheckStateSimpleGraph) {
|
|||||||
query::DumpDatabaseToCypherQueries(&dba, &query_stream);
|
query::DumpDatabaseToCypherQueries(&dba, &query_stream);
|
||||||
}
|
}
|
||||||
const auto &results = stream.GetResults();
|
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.
|
// query for the data.
|
||||||
ASSERT_GE(results.size(), 4);
|
ASSERT_GE(results.size(), 5);
|
||||||
for (const auto &item : results) {
|
for (const auto &item : results) {
|
||||||
ASSERT_EQ(item.size(), 1);
|
ASSERT_EQ(item.size(), 1);
|
||||||
ASSERT_TRUE(item[0].IsString());
|
ASSERT_TRUE(item[0].IsString());
|
||||||
|
Loading…
Reference in New Issue
Block a user