GraphDdAccessor and KeyIndex API upgrades. Test refactoring
Summary: The GraphDbAccessor and KeyIndex APIs can now also return records for the current transaction+command graph state. This is necessary to correctly implement MERGE. The new logic is has increased the MVCC+Accessor related chaos and should be revised when refactoring MVCC (as planned). Previous index testing was separated into VertexIndex and EdgeIndex testing. This is inappropriate since most of the logic is exaclty the same. Also it was not clearly defined what gets tested via the GraphDbAccessor API, and what directly through the KeyIndex API. This has also been refactored, but it needs additional work (Gleich). Reviewers: buda, dgleich Reviewed By: buda, dgleich Subscribers: pullbot Differential Revision: https://phabricator.memgraph.io/D306
This commit is contained in:
parent
355f62ce71
commit
0a33a555a6
@ -51,8 +51,12 @@ void GraphDbAccessor::update_label_index(const GraphDbTypes::Label &label,
|
||||
this->db_.labels_index_.Update(label, vertex_accessor.vlist_, vertex);
|
||||
}
|
||||
|
||||
size_t GraphDbAccessor::vertices_count(const GraphDbTypes::Label &label) {
|
||||
return this->db_.labels_index_.Count(label);
|
||||
size_t GraphDbAccessor::vertices_count() const {
|
||||
return db_.vertices_.access().size();
|
||||
}
|
||||
|
||||
size_t GraphDbAccessor::vertices_count(const GraphDbTypes::Label &label) const {
|
||||
return db_.labels_index_.Count(label);
|
||||
}
|
||||
|
||||
bool GraphDbAccessor::remove_vertex(VertexAccessor &vertex_accessor) {
|
||||
@ -111,8 +115,13 @@ void GraphDbAccessor::update_edge_type_index(
|
||||
this->db_.edge_types_index_.Update(edge_type, edge_accessor.vlist_, edge);
|
||||
}
|
||||
|
||||
size_t GraphDbAccessor::edges_count(const GraphDbTypes::EdgeType &edge_type) {
|
||||
return this->db_.edge_types_index_.Count(edge_type);
|
||||
size_t GraphDbAccessor::edges_count() const {
|
||||
return db_.edges_.access().size();
|
||||
}
|
||||
|
||||
size_t GraphDbAccessor::edges_count(
|
||||
const GraphDbTypes::EdgeType &edge_type) const {
|
||||
return db_.edge_types_index_.Count(edge_type);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -78,8 +78,13 @@ class GraphDbAccessor {
|
||||
/**
|
||||
* Returns iterable over accessors to all the vertices in the graph
|
||||
* visible to the current transaction.
|
||||
*
|
||||
* @param current_state If true then the graph state for the
|
||||
* current transaction+command is returned (insertions, updates and
|
||||
* deletions performed in the current transaction+command are not
|
||||
* ignored).
|
||||
*/
|
||||
auto vertices() {
|
||||
auto vertices(bool current_state = false) {
|
||||
// wrap version lists into accessors, which will look for visible versions
|
||||
auto accessors =
|
||||
iter::imap([this](auto vlist) { return VertexAccessor(*vlist, *this); },
|
||||
@ -87,8 +92,12 @@ class GraphDbAccessor {
|
||||
|
||||
// filter out the accessors not visible to the current transaction
|
||||
return iter::filter(
|
||||
[this](const VertexAccessor &accessor) {
|
||||
return accessor.old_ != nullptr;
|
||||
[this, current_state](const VertexAccessor &accessor) {
|
||||
return (accessor.old_ &&
|
||||
!(current_state &&
|
||||
accessor.old_->is_deleted_by(*transaction_))) ||
|
||||
(current_state && accessor.new_ &&
|
||||
!accessor.new_->is_deleted_by(*transaction_));
|
||||
},
|
||||
std::move(accessors));
|
||||
}
|
||||
@ -97,12 +106,18 @@ class GraphDbAccessor {
|
||||
* Return VertexAccessors which contain the current label for the current
|
||||
* transaction visibilty.
|
||||
* @param label - label for which to return VertexAccessors
|
||||
* @param current_state If true then the graph state for the
|
||||
* current transaction+command is returned (insertions, updates and
|
||||
* deletions performed in the current transaction+command are not
|
||||
* ignored).
|
||||
* @return iterable collection
|
||||
*/
|
||||
auto vertices(const GraphDbTypes::Label &label) {
|
||||
auto vertices(const GraphDbTypes::Label &label, bool current_state = false) {
|
||||
return iter::imap(
|
||||
[this](auto vlist) { return VertexAccessor(*vlist, *this); },
|
||||
db_.labels_index_.GetVlists(label, *transaction_));
|
||||
[this, current_state](auto vlist) {
|
||||
return VertexAccessor(*vlist, *this);
|
||||
},
|
||||
db_.labels_index_.GetVlists(label, *transaction_, current_state));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -126,8 +141,13 @@ class GraphDbAccessor {
|
||||
/**
|
||||
* Returns iterable over accessors to all the edges in the graph
|
||||
* visible to the current transaction.
|
||||
*
|
||||
* @param current_state If true then the graph state for the
|
||||
* current transaction+command is returned (insertions, updates and
|
||||
* deletions performed in the current transaction+command are not
|
||||
* ignored).
|
||||
*/
|
||||
auto edges() {
|
||||
auto edges(bool current_state = false) {
|
||||
// wrap version lists into accessors, which will look for visible versions
|
||||
auto accessors =
|
||||
iter::imap([this](auto vlist) { return EdgeAccessor(*vlist, *this); },
|
||||
@ -135,22 +155,32 @@ class GraphDbAccessor {
|
||||
|
||||
// filter out the accessors not visible to the current transaction
|
||||
return iter::filter(
|
||||
[this](const EdgeAccessor &accessor) {
|
||||
return accessor.old_ != nullptr;
|
||||
[this, current_state](const EdgeAccessor &accessor) {
|
||||
return (accessor.old_ &&
|
||||
!(current_state &&
|
||||
accessor.old_->is_deleted_by(*transaction_))) ||
|
||||
(current_state && accessor.new_ &&
|
||||
!accessor.new_->is_deleted_by(*transaction_));
|
||||
},
|
||||
std::move(accessors));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return EdgeAccessors which contain the edge_type for the current
|
||||
* transaction visibilty.
|
||||
* transaction visibility.
|
||||
* @param edge_type - edge_type for which to return EdgeAccessors
|
||||
* @param current_state If true then the graph state for the
|
||||
* current transaction+command is returned (insertions, updates and
|
||||
* deletions performed in the current transaction+command are not
|
||||
* ignored).
|
||||
* @return iterable collection
|
||||
*/
|
||||
auto edges(const GraphDbTypes::EdgeType &edge_type) {
|
||||
return iter::imap(
|
||||
[this](auto vlist) { return EdgeAccessor(*vlist, *this); },
|
||||
db_.edge_types_index_.GetVlists(edge_type, *transaction_));
|
||||
auto edges(const GraphDbTypes::EdgeType &edge_type,
|
||||
bool current_state = false) {
|
||||
return iter::imap([this, current_state](
|
||||
auto vlist) { return EdgeAccessor(*vlist, *this); },
|
||||
db_.edge_types_index_.GetVlists(edge_type, *transaction_,
|
||||
current_state));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -173,13 +203,25 @@ class GraphDbAccessor {
|
||||
const EdgeAccessor &edge_accessor,
|
||||
const Edge *edge);
|
||||
|
||||
/**
|
||||
* Return approximate number of all vertices in the database.
|
||||
* Note that this is always an over-estimate and never an under-estimate.
|
||||
*/
|
||||
size_t vertices_count() const;
|
||||
|
||||
/*
|
||||
* Return approximate number of all edges in the database.
|
||||
* Note that this is always an over-estimate and never an under-estimate.
|
||||
*/
|
||||
size_t edges_count() const;
|
||||
|
||||
/**
|
||||
* Return approximate number of vertices under indexes with the given label.
|
||||
* Note that this is always an over-estimate and never an under-estimate.
|
||||
* @param label - label to check for
|
||||
* @return number of vertices with the given label
|
||||
*/
|
||||
size_t vertices_count(const GraphDbTypes::Label &label);
|
||||
size_t vertices_count(const GraphDbTypes::Label &label) const;
|
||||
|
||||
/**
|
||||
* Return approximate number of edges under indexes with the given edge_type.
|
||||
@ -187,7 +229,7 @@ class GraphDbAccessor {
|
||||
* @param edge_type - edge_type to check for
|
||||
* @return number of edges with the given edge_type
|
||||
*/
|
||||
size_t edges_count(const GraphDbTypes::EdgeType &edge_type);
|
||||
size_t edges_count(const GraphDbTypes::EdgeType &edge_type) const;
|
||||
|
||||
/**
|
||||
* Obtains the Label for the label's name.
|
||||
@ -258,7 +300,7 @@ class GraphDbAccessor {
|
||||
*/
|
||||
template <typename TRecord>
|
||||
bool Reconstruct(RecordAccessor<TRecord> &accessor) {
|
||||
accessor.vlist_->find_set_new_old(*transaction_, accessor.old_,
|
||||
accessor.vlist_->find_set_old_new(*transaction_, accessor.old_,
|
||||
accessor.new_);
|
||||
accessor.current_ = accessor.old_ ? accessor.old_ : accessor.new_;
|
||||
return accessor.old_ != nullptr || accessor.new_ != nullptr;
|
||||
|
@ -44,19 +44,40 @@ class KeyIndex {
|
||||
* still have that label visible in this transaction.
|
||||
* @param key - key to query.
|
||||
* @param t - current transaction, which determines visibility.
|
||||
* @param current_state If true then the graph state for the
|
||||
* current transaction+command is returned (insertions, updates and
|
||||
* deletions performed in the current transaction+command are not
|
||||
* ignored).
|
||||
* @return iterable collection of vlists records<TRecord> with the requested
|
||||
* TKey.
|
||||
*/
|
||||
auto GetVlists(const TKey &key, tx::Transaction &t) {
|
||||
auto GetVlists(const TKey &key, tx::Transaction &t,
|
||||
bool current_state = false) {
|
||||
auto index = GetKeyStorage(key);
|
||||
mvcc::VersionList<TRecord> *prev = nullptr;
|
||||
auto filtered = iter::filter(
|
||||
[this, &key, &t, prev](auto entry) mutable {
|
||||
[this, &key, &t, prev, current_state](auto entry) mutable {
|
||||
// we check for previous match first as an optimization
|
||||
// it's legal because if the first v-list pair does not
|
||||
// pass, neither will any other identical one
|
||||
if (entry.vlist_ == prev) return false;
|
||||
auto version = entry.vlist_->find(t);
|
||||
prev = entry.vlist_;
|
||||
if (version == nullptr) return false;
|
||||
return Exists(key, version);
|
||||
// TODO when refactoring MVCC reconsider the return-value-arg idiom here
|
||||
TRecord *old_record, *new_record;
|
||||
entry.vlist_->find_set_old_new(t, old_record, new_record);
|
||||
// filtering out records not visible to the current
|
||||
// transaction+command
|
||||
// taking into account the current_state flag
|
||||
bool visible =
|
||||
(old_record &&
|
||||
!(current_state && old_record->is_deleted_by(t))) ||
|
||||
(current_state && new_record && !new_record->is_deleted_by(t));
|
||||
if (!visible) return false;
|
||||
// if we current_state and we have the new record, then that's the
|
||||
// reference value, and that needs to be compared with the index
|
||||
// predicate
|
||||
return (current_state && new_record) ? Exists(key, new_record)
|
||||
: Exists(key, old_record);
|
||||
},
|
||||
index->access());
|
||||
return iter::imap([this](auto entry) { return entry.vlist_; },
|
||||
|
@ -178,7 +178,7 @@ class VersionList {
|
||||
*
|
||||
* @param t The transaction
|
||||
*/
|
||||
void find_set_new_old(const tx::Transaction &t, T *&old_ref, T *&new_ref) {
|
||||
void find_set_old_new(const tx::Transaction &t, T *&old_ref, T *&new_ref) {
|
||||
// assume that the sought old record is further down the list
|
||||
// from new record, so that if we found old we can stop looking
|
||||
new_ref = nullptr;
|
||||
|
@ -188,12 +188,8 @@ std::unique_ptr<Cursor> ScanAll::MakeCursor(GraphDbAccessor &db) {
|
||||
ScanAll::ScanAllCursor::ScanAllCursor(const ScanAll &self, GraphDbAccessor &db)
|
||||
: self_(self),
|
||||
input_cursor_(self.input_->MakeCursor(db)),
|
||||
// TODO change to db.vertices(self.graph_view_ == GraphView::NEW)
|
||||
// once this GraphDbAccessor API is available
|
||||
vertices_(db.vertices()),
|
||||
vertices_it_(vertices_.end()) {
|
||||
if (self.graph_view_ == GraphView::NEW) throw utils::NotYetImplemented();
|
||||
}
|
||||
vertices_(db.vertices(self.graph_view_ == GraphView::NEW)),
|
||||
vertices_it_(vertices_.end()) {}
|
||||
|
||||
bool ScanAll::ScanAllCursor::Pull(Frame &frame,
|
||||
const SymbolTable &symbol_table) {
|
||||
|
@ -2,66 +2,46 @@
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "data_structures/ptr_int.hpp"
|
||||
#include "database/graph_db_accessor.hpp"
|
||||
#include "database/graph_db_datatypes.hpp"
|
||||
#include "database/graph_db_accessor.hpp"
|
||||
#include "dbms/dbms.hpp"
|
||||
#include "storage/vertex.hpp"
|
||||
|
||||
using testing::UnorderedElementsAreArray;
|
||||
|
||||
// Test counter of indexed vertices with the given label.
|
||||
TEST(LabelsIndex, Count) {
|
||||
Dbms dbms;
|
||||
auto accessor = dbms.active();
|
||||
const int ITERS = 50;
|
||||
size_t cnt = 0;
|
||||
for (int i = 0; i < ITERS; ++i) {
|
||||
auto vertex = accessor->insert_vertex();
|
||||
if (rand() & 1) {
|
||||
vertex.add_label(accessor->label("test"));
|
||||
++cnt;
|
||||
} else {
|
||||
vertex.add_label(accessor->label("test2"));
|
||||
}
|
||||
// Greater or equal since we said that we always estimate at least the
|
||||
// real number.
|
||||
EXPECT_GE(accessor->vertices_count(accessor->label("test")), cnt);
|
||||
}
|
||||
}
|
||||
|
||||
// Test index does it insert everything uniquely
|
||||
TEST(LabelsIndex, UniqueInsert) {
|
||||
KeyIndex<GraphDbTypes::Label, Vertex> index;
|
||||
Dbms dbms;
|
||||
auto access = dbms.active();
|
||||
auto dba = dbms.active();
|
||||
tx::Engine engine;
|
||||
auto t1 = engine.begin();
|
||||
mvcc::VersionList<Vertex> vlist(*t1);
|
||||
t1->commit();
|
||||
auto t2 = engine.begin();
|
||||
|
||||
vlist.find(*t2)->labels_.push_back(access->label("1"));
|
||||
index.Update(access->label("1"), &vlist, vlist.find(*t2));
|
||||
vlist.find(*t2)->labels_.push_back(dba->label("1"));
|
||||
index.Update(dba->label("1"), &vlist, vlist.find(*t2));
|
||||
// Try multiple inserts
|
||||
index.Update(access->label("1"), &vlist, vlist.find(*t2));
|
||||
index.Update(dba->label("1"), &vlist, vlist.find(*t2));
|
||||
|
||||
vlist.find(*t2)->labels_.push_back(access->label("2"));
|
||||
index.Update(access->label("2"), &vlist, vlist.find(*t2));
|
||||
vlist.find(*t2)->labels_.push_back(dba->label("2"));
|
||||
index.Update(dba->label("2"), &vlist, vlist.find(*t2));
|
||||
|
||||
vlist.find(*t2)->labels_.push_back(access->label("3"));
|
||||
index.Update(access->label("3"), &vlist, vlist.find(*t2));
|
||||
vlist.find(*t2)->labels_.push_back(dba->label("3"));
|
||||
index.Update(dba->label("3"), &vlist, vlist.find(*t2));
|
||||
t2->commit();
|
||||
|
||||
EXPECT_EQ(index.Count(access->label("1")), 1);
|
||||
EXPECT_EQ(index.Count(access->label("2")), 1);
|
||||
EXPECT_EQ(index.Count(access->label("3")), 1);
|
||||
EXPECT_EQ(index.Count(dba->label("1")), 1);
|
||||
EXPECT_EQ(index.Count(dba->label("2")), 1);
|
||||
EXPECT_EQ(index.Count(dba->label("3")), 1);
|
||||
}
|
||||
|
||||
// Check if index filters duplicates.
|
||||
TEST(LabelsIndex, UniqueFilter) {
|
||||
KeyIndex<GraphDbTypes::Label, Vertex> index;
|
||||
Dbms dbms;
|
||||
auto access = dbms.active();
|
||||
auto dba = dbms.active();
|
||||
tx::Engine engine;
|
||||
|
||||
auto t1 = engine.begin();
|
||||
@ -70,10 +50,10 @@ TEST(LabelsIndex, UniqueFilter) {
|
||||
t1->engine.advance(
|
||||
t1->id); // advance command so we can see our inserted version
|
||||
auto r1v1 = vlist1.find(*t1);
|
||||
auto r1v2 = vlist1.find(*t1);
|
||||
auto r1v2 = vlist2.find(*t1);
|
||||
EXPECT_NE(vlist1.find(*t1), nullptr);
|
||||
|
||||
auto label1 = access->label("1");
|
||||
auto label1 = dba->label("1");
|
||||
vlist1.find(*t1)->labels_.push_back(label1);
|
||||
vlist2.find(*t1)->labels_.push_back(label1);
|
||||
index.Update(label1, &vlist1, r1v1);
|
||||
@ -140,10 +120,10 @@ TEST(LabelsIndex, Refresh) {
|
||||
// Transaction hasn't ended and so the vertex is not visible.
|
||||
TEST(LabelsIndexDb, AddGetZeroLabels) {
|
||||
Dbms dbms;
|
||||
auto accessor = dbms.active();
|
||||
auto vertex = accessor->insert_vertex();
|
||||
vertex.add_label(accessor->label("test"));
|
||||
auto collection = accessor->vertices(accessor->label("test"));
|
||||
auto dba = dbms.active();
|
||||
auto vertex = dba->insert_vertex();
|
||||
vertex.add_label(dba->label("test"));
|
||||
auto collection = dba->vertices(dba->label("test"));
|
||||
std::vector<VertexAccessor> collection_vector(collection.begin(),
|
||||
collection.end());
|
||||
EXPECT_EQ(collection_vector.size(), (size_t)0);
|
||||
@ -154,61 +134,61 @@ TEST(LabelsIndexDb, AddGetZeroLabels) {
|
||||
TEST(LabelsIndexDb, AddGetRemoveLabel) {
|
||||
Dbms dbms;
|
||||
{
|
||||
auto accessor = dbms.active();
|
||||
auto dba = dbms.active();
|
||||
|
||||
auto vertex1 = accessor->insert_vertex();
|
||||
vertex1.add_label(accessor->label("test"));
|
||||
auto vertex1 = dba->insert_vertex();
|
||||
vertex1.add_label(dba->label("test"));
|
||||
|
||||
auto vertex2 = accessor->insert_vertex();
|
||||
vertex2.add_label(accessor->label("test2"));
|
||||
auto vertex2 = dba->insert_vertex();
|
||||
vertex2.add_label(dba->label("test2"));
|
||||
|
||||
auto vertex3 = accessor->insert_vertex();
|
||||
vertex3.add_label(accessor->label("test"));
|
||||
auto vertex3 = dba->insert_vertex();
|
||||
vertex3.add_label(dba->label("test"));
|
||||
|
||||
accessor->commit();
|
||||
dba->commit();
|
||||
} // Finish transaction.
|
||||
{
|
||||
auto accessor = dbms.active();
|
||||
auto dba = dbms.active();
|
||||
|
||||
auto filtered = accessor->vertices(accessor->label("test"));
|
||||
auto filtered = dba->vertices(dba->label("test"));
|
||||
std::vector<VertexAccessor> collection(filtered.begin(), filtered.end());
|
||||
auto vertices = accessor->vertices();
|
||||
auto vertices = dba->vertices();
|
||||
|
||||
std::vector<VertexAccessor> expected_collection;
|
||||
for (auto vertex : vertices) {
|
||||
if (vertex.has_label(accessor->label("test"))) {
|
||||
if (vertex.has_label(dba->label("test"))) {
|
||||
expected_collection.push_back(vertex);
|
||||
} else {
|
||||
EXPECT_TRUE(vertex.has_label(accessor->label("test2")));
|
||||
EXPECT_TRUE(vertex.has_label(dba->label("test2")));
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_EQ(expected_collection.size(), collection.size());
|
||||
EXPECT_TRUE(collection[0].has_label(accessor->label("test")));
|
||||
EXPECT_TRUE(collection[1].has_label(accessor->label("test")));
|
||||
EXPECT_FALSE(collection[0].has_label(accessor->label("test2")));
|
||||
EXPECT_FALSE(collection[1].has_label(accessor->label("test2")));
|
||||
accessor->remove_vertex(collection[0]); // Remove from database and test if
|
||||
// index won't return it.
|
||||
EXPECT_TRUE(collection[0].has_label(dba->label("test")));
|
||||
EXPECT_TRUE(collection[1].has_label(dba->label("test")));
|
||||
EXPECT_FALSE(collection[0].has_label(dba->label("test2")));
|
||||
EXPECT_FALSE(collection[1].has_label(dba->label("test2")));
|
||||
dba->remove_vertex(collection[0]); // Remove from database and test if
|
||||
// index won't return it.
|
||||
|
||||
// Remove label from the vertex and add new label.
|
||||
collection[1].remove_label(accessor->label("test"));
|
||||
collection[1].add_label(accessor->label("test2"));
|
||||
accessor->commit();
|
||||
collection[1].remove_label(dba->label("test"));
|
||||
collection[1].add_label(dba->label("test2"));
|
||||
dba->commit();
|
||||
}
|
||||
{
|
||||
auto accessor = dbms.active();
|
||||
auto dba = dbms.active();
|
||||
|
||||
auto filtered = accessor->vertices(accessor->label("test"));
|
||||
auto filtered = dba->vertices(dba->label("test"));
|
||||
std::vector<VertexAccessor> collection(filtered.begin(), filtered.end());
|
||||
auto vertices = accessor->vertices();
|
||||
auto vertices = dba->vertices();
|
||||
|
||||
std::vector<VertexAccessor> expected_collection;
|
||||
for (auto vertex : vertices) {
|
||||
if (vertex.has_label(accessor->label("test"))) {
|
||||
if (vertex.has_label(dba->label("test"))) {
|
||||
expected_collection.push_back(vertex);
|
||||
} else {
|
||||
EXPECT_TRUE(vertex.has_label(accessor->label("test2")));
|
||||
EXPECT_TRUE(vertex.has_label(dba->label("test2")));
|
||||
}
|
||||
}
|
||||
|
||||
@ -219,6 +199,8 @@ TEST(LabelsIndexDb, AddGetRemoveLabel) {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO gleich - discuss with Flor the API changes and the tests
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
@ -1,119 +0,0 @@
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "data_structures/ptr_int.hpp"
|
||||
#include "database/graph_db_accessor.hpp"
|
||||
#include "dbms/dbms.hpp"
|
||||
|
||||
using testing::UnorderedElementsAreArray;
|
||||
|
||||
// Test counter of indexed edges with the given edge_type.
|
||||
TEST(EdgeTypesIndex, Count) {
|
||||
Dbms dbms;
|
||||
auto accessor = dbms.active();
|
||||
const int ITERS = 50;
|
||||
size_t cnt = 0;
|
||||
for (int i = 0; i < ITERS; ++i) {
|
||||
auto vertex1 = accessor->insert_vertex();
|
||||
auto vertex2 = accessor->insert_vertex();
|
||||
if (rand() & 1) {
|
||||
accessor->insert_edge(vertex1, vertex2, accessor->edge_type("test"));
|
||||
++cnt;
|
||||
} else {
|
||||
accessor->insert_edge(vertex1, vertex2, accessor->edge_type("test2"));
|
||||
}
|
||||
// Greater or equal since we said that we always estimate at least the
|
||||
// real number.
|
||||
EXPECT_GE(accessor->edges_count(accessor->edge_type("test")), cnt);
|
||||
}
|
||||
}
|
||||
|
||||
// Transaction hasn't ended and so the edge is not visible.
|
||||
TEST(EdgeTypesIndex, AddGetZeroEdgeTypes) {
|
||||
Dbms dbms;
|
||||
auto accessor = dbms.active();
|
||||
auto vertex1 = accessor->insert_vertex();
|
||||
auto vertex2 = accessor->insert_vertex();
|
||||
accessor->insert_edge(vertex1, vertex2, accessor->edge_type("test"));
|
||||
auto collection = accessor->edges(accessor->edge_type("test"));
|
||||
std::vector<EdgeAccessor> collection_vector(collection.begin(),
|
||||
collection.end());
|
||||
EXPECT_EQ(collection_vector.size(), (size_t)0);
|
||||
}
|
||||
|
||||
// Test edge type index by adding and removing one edge, checking edge_type of
|
||||
// another, while the third one with an irrelevant edge_type exists.
|
||||
TEST(LabelsIndex, AddGetRemoveEdgeTypes) {
|
||||
Dbms dbms;
|
||||
{
|
||||
auto accessor = dbms.active();
|
||||
|
||||
auto vertex11 = accessor->insert_vertex();
|
||||
auto vertex12 = accessor->insert_vertex();
|
||||
accessor->insert_edge(vertex11, vertex12, accessor->edge_type("test"));
|
||||
|
||||
auto vertex21 = accessor->insert_vertex();
|
||||
auto vertex22 = accessor->insert_vertex();
|
||||
accessor->insert_edge(vertex21, vertex22, accessor->edge_type("test2"));
|
||||
|
||||
auto vertex31 = accessor->insert_vertex();
|
||||
auto vertex32 = accessor->insert_vertex();
|
||||
accessor->insert_edge(vertex31, vertex32, accessor->edge_type("test"));
|
||||
|
||||
accessor->commit();
|
||||
} // Finish transaction.
|
||||
{
|
||||
auto accessor = dbms.active();
|
||||
|
||||
auto filtered = accessor->edges(accessor->edge_type("test"));
|
||||
std::vector<EdgeAccessor> collection(filtered.begin(), filtered.end());
|
||||
auto edges = accessor->edges();
|
||||
|
||||
std::vector<EdgeAccessor> expected_collection;
|
||||
for (auto edge : edges) {
|
||||
if (edge.edge_type() == accessor->edge_type("test")) {
|
||||
expected_collection.push_back(edge);
|
||||
} else {
|
||||
EXPECT_TRUE(edge.edge_type() == accessor->edge_type("test2"));
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_EQ(expected_collection.size(), collection.size());
|
||||
EXPECT_TRUE(collection[0].edge_type() == accessor->edge_type("test"));
|
||||
EXPECT_TRUE(collection[1].edge_type() == accessor->edge_type("test"));
|
||||
EXPECT_FALSE(collection[0].edge_type() == accessor->edge_type("test2"));
|
||||
EXPECT_FALSE(collection[1].edge_type() == accessor->edge_type("test2"));
|
||||
accessor->remove_edge(collection[0]); // Remove from database and test if
|
||||
// index won't return it.
|
||||
accessor->remove_edge(collection[1]); // Remove from database and test if
|
||||
// index won't return it.
|
||||
|
||||
accessor->commit();
|
||||
}
|
||||
{
|
||||
auto accessor = dbms.active();
|
||||
|
||||
auto filtered = accessor->edges(accessor->edge_type("test"));
|
||||
std::vector<EdgeAccessor> collection(filtered.begin(), filtered.end());
|
||||
auto edges = accessor->edges();
|
||||
|
||||
std::vector<EdgeAccessor> expected_collection;
|
||||
for (auto edge : edges) {
|
||||
if (edge.edge_type() == accessor->edge_type("test")) {
|
||||
expected_collection.push_back(edge);
|
||||
} else {
|
||||
EXPECT_TRUE(edge.edge_type() == accessor->edge_type("test2"));
|
||||
}
|
||||
}
|
||||
|
||||
// It should be empty since everything with an old edge_type is either
|
||||
// deleted or doesn't have that edge_type anymore.
|
||||
EXPECT_EQ(expected_collection.size(), 0);
|
||||
EXPECT_EQ(collection.size(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
@ -7,18 +7,10 @@
|
||||
#include "storage/edge_accessor.hpp"
|
||||
#include "storage/vertex_accessor.hpp"
|
||||
|
||||
size_t CountVertices(GraphDbAccessor &db_accessor) {
|
||||
size_t r_val = 0;
|
||||
for ([[gnu::unused]] auto va : db_accessor.vertices()) r_val++;
|
||||
|
||||
return r_val;
|
||||
}
|
||||
|
||||
size_t CountEdges(GraphDbAccessor &db_accessor) {
|
||||
size_t r_val = 0;
|
||||
for ([[gnu::unused]] auto va : db_accessor.edges()) r_val++;
|
||||
|
||||
return r_val;
|
||||
template <typename TIterable>
|
||||
auto Count(TIterable iterable) {
|
||||
return std::distance(iterable.begin(), iterable.end());
|
||||
}
|
||||
|
||||
TEST(GraphDbAccessorTest, DbmsCreateDefault) {
|
||||
@ -31,31 +23,37 @@ TEST(GraphDbAccessorTest, InsertVertex) {
|
||||
Dbms dbms;
|
||||
auto accessor = dbms.active();
|
||||
|
||||
EXPECT_EQ(CountVertices(*accessor), 0);
|
||||
EXPECT_EQ(Count(accessor->vertices()), 0);
|
||||
|
||||
accessor->insert_vertex();
|
||||
EXPECT_EQ(Count(accessor->vertices()), 0);
|
||||
EXPECT_EQ(Count(accessor->vertices(true)), 1);
|
||||
accessor->advance_command();
|
||||
EXPECT_EQ(CountVertices(*accessor), 1);
|
||||
EXPECT_EQ(Count(accessor->vertices()), 1);
|
||||
|
||||
accessor->insert_vertex();
|
||||
EXPECT_EQ(Count(accessor->vertices()), 1);
|
||||
EXPECT_EQ(Count(accessor->vertices(true)), 2);
|
||||
accessor->advance_command();
|
||||
EXPECT_EQ(CountVertices(*accessor), 2);
|
||||
EXPECT_EQ(Count(accessor->vertices()), 2);
|
||||
}
|
||||
|
||||
TEST(GraphDbAccessorTest, RemoveVertexSameTransaction) {
|
||||
Dbms dbms;
|
||||
auto accessor = dbms.active();
|
||||
|
||||
EXPECT_EQ(CountVertices(*accessor), 0);
|
||||
EXPECT_EQ(Count(accessor->vertices()), 0);
|
||||
|
||||
auto va1 = accessor->insert_vertex();
|
||||
accessor->advance_command();
|
||||
EXPECT_EQ(CountVertices(*accessor), 1);
|
||||
EXPECT_EQ(Count(accessor->vertices()), 1);
|
||||
|
||||
EXPECT_TRUE(accessor->remove_vertex(va1));
|
||||
EXPECT_EQ(CountVertices(*accessor), 1);
|
||||
EXPECT_EQ(Count(accessor->vertices()), 1);
|
||||
EXPECT_EQ(Count(accessor->vertices(true)), 0);
|
||||
accessor->advance_command();
|
||||
EXPECT_EQ(CountVertices(*accessor), 0);
|
||||
EXPECT_EQ(Count(accessor->vertices()), 0);
|
||||
EXPECT_EQ(Count(accessor->vertices(true)), 0);
|
||||
}
|
||||
|
||||
TEST(GraphDbAccessorTest, RemoveVertexDifferentTransaction) {
|
||||
@ -68,14 +66,16 @@ TEST(GraphDbAccessorTest, RemoveVertexDifferentTransaction) {
|
||||
|
||||
// second transaction checks that it sees it, and deletes it
|
||||
auto accessor2 = dbms.active();
|
||||
EXPECT_EQ(CountVertices(*accessor2), 1);
|
||||
EXPECT_EQ(Count(accessor2->vertices()), 1);
|
||||
EXPECT_EQ(Count(accessor2->vertices(true)), 1);
|
||||
for (auto vertex_accessor : accessor2->vertices())
|
||||
accessor2->remove_vertex(vertex_accessor);
|
||||
accessor2->commit();
|
||||
|
||||
// third transaction checks that it does not see the vertex
|
||||
auto accessor3 = dbms.active();
|
||||
EXPECT_EQ(CountVertices(*accessor3), 0);
|
||||
EXPECT_EQ(Count(accessor3->vertices()), 0);
|
||||
EXPECT_EQ(Count(accessor3->vertices(true)), 0);
|
||||
}
|
||||
|
||||
TEST(GraphDbAccessorTest, InsertEdge) {
|
||||
@ -92,8 +92,11 @@ TEST(GraphDbAccessorTest, InsertEdge) {
|
||||
|
||||
// setup (v1) - [:likes] -> (v2)
|
||||
dba->insert_edge(va1, va2, dba->edge_type("likes"));
|
||||
EXPECT_EQ(Count(dba->edges()), 0);
|
||||
EXPECT_EQ(Count(dba->edges(true)), 1);
|
||||
dba->advance_command();
|
||||
EXPECT_EQ(CountEdges(*dba), 1);
|
||||
EXPECT_EQ(Count(dba->edges()), 1);
|
||||
EXPECT_EQ(Count(dba->edges(true)), 1);
|
||||
EXPECT_EQ(va1.out().begin()->to(), va2);
|
||||
EXPECT_EQ(va2.in().begin()->from(), va1);
|
||||
EXPECT_EQ(va1.in_degree(), 0);
|
||||
@ -104,8 +107,10 @@ TEST(GraphDbAccessorTest, InsertEdge) {
|
||||
// setup (v1) - [:likes] -> (v2) <- [:hates] - (v3)
|
||||
auto va3 = dba->insert_vertex();
|
||||
dba->insert_edge(va3, va2, dba->edge_type("hates"));
|
||||
EXPECT_EQ(Count(dba->edges(false)), 1);
|
||||
EXPECT_EQ(Count(dba->edges(true)), 2);
|
||||
dba->advance_command();
|
||||
EXPECT_EQ(CountEdges(*dba), 2);
|
||||
EXPECT_EQ(Count(dba->edges()), 2);
|
||||
EXPECT_EQ(va3.out().begin()->to(), va2);
|
||||
EXPECT_EQ(va1.in_degree(), 0);
|
||||
EXPECT_EQ(va1.out_degree(), 1);
|
||||
@ -126,17 +131,21 @@ TEST(GraphDbAccessorTest, RemoveEdge) {
|
||||
dba->insert_edge(va1, va2, dba->edge_type("likes"));
|
||||
dba->insert_edge(va3, va2, dba->edge_type("hates"));
|
||||
dba->advance_command();
|
||||
EXPECT_EQ(CountEdges(*dba), 2);
|
||||
EXPECT_EQ(Count(dba->edges()), 2);
|
||||
EXPECT_EQ(Count(dba->edges(true)), 2);
|
||||
|
||||
// remove all [:hates] edges
|
||||
EXPECT_EQ(CountEdges(*dba), 2);
|
||||
for (auto edge : dba->edges())
|
||||
if (edge.edge_type() == dba->edge_type("hates")) dba->remove_edge(edge);
|
||||
EXPECT_EQ(Count(dba->edges()), 2);
|
||||
EXPECT_EQ(Count(dba->edges(true)), 1);
|
||||
|
||||
// current state: (v1) - [:likes] -> (v2), (v3)
|
||||
dba->advance_command();
|
||||
EXPECT_EQ(CountEdges(*dba), 1);
|
||||
EXPECT_EQ(CountVertices(*dba), 3);
|
||||
EXPECT_EQ(Count(dba->edges()), 1);
|
||||
EXPECT_EQ(Count(dba->edges(true)), 1);
|
||||
EXPECT_EQ(Count(dba->vertices()), 3);
|
||||
EXPECT_EQ(Count(dba->vertices(true)), 3);
|
||||
for (auto edge : dba->edges()) {
|
||||
EXPECT_EQ(edge.edge_type(), dba->edge_type("likes"));
|
||||
auto v1 = edge.from();
|
||||
@ -175,50 +184,58 @@ TEST(GraphDbAccessorTest, DetachRemoveVertex) {
|
||||
for (auto &vertex : vertices) vertex.Reconstruct();
|
||||
|
||||
// ensure that plain remove does NOT work
|
||||
EXPECT_EQ(CountVertices(*dba), 4);
|
||||
EXPECT_EQ(CountEdges(*dba), 3);
|
||||
EXPECT_EQ(Count(dba->vertices()), 4);
|
||||
EXPECT_EQ(Count(dba->edges()), 3);
|
||||
EXPECT_FALSE(dba->remove_vertex(vertices[0]));
|
||||
EXPECT_FALSE(dba->remove_vertex(vertices[1]));
|
||||
EXPECT_FALSE(dba->remove_vertex(vertices[2]));
|
||||
EXPECT_EQ(CountVertices(*dba), 4);
|
||||
EXPECT_EQ(CountEdges(*dba), 3);
|
||||
EXPECT_EQ(Count(dba->vertices()), 4);
|
||||
EXPECT_EQ(Count(dba->edges()), 3);
|
||||
|
||||
dba->detach_remove_vertex(vertices[2]);
|
||||
EXPECT_EQ(Count(dba->vertices()), 4);
|
||||
EXPECT_EQ(Count(dba->vertices(true)), 3);
|
||||
EXPECT_EQ(Count(dba->edges()), 3);
|
||||
EXPECT_EQ(Count(dba->edges(true)), 1);
|
||||
dba->advance_command();
|
||||
for (auto &vertex : vertices) vertex.Reconstruct();
|
||||
|
||||
EXPECT_EQ(CountVertices(*dba), 3);
|
||||
EXPECT_EQ(CountEdges(*dba), 1);
|
||||
EXPECT_EQ(Count(dba->vertices()), 3);
|
||||
EXPECT_EQ(Count(dba->edges()), 1);
|
||||
EXPECT_TRUE(dba->remove_vertex(vertices[3]));
|
||||
EXPECT_EQ(Count(dba->vertices(true)), 2);
|
||||
EXPECT_EQ(Count(dba->vertices()), 3);
|
||||
dba->advance_command();
|
||||
for (auto &vertex : vertices) vertex.Reconstruct();
|
||||
|
||||
EXPECT_EQ(CountVertices(*dba), 2);
|
||||
EXPECT_EQ(CountEdges(*dba), 1);
|
||||
EXPECT_EQ(Count(dba->vertices()), 2);
|
||||
EXPECT_EQ(Count(dba->edges()), 1);
|
||||
for (auto va : dba->vertices()) EXPECT_FALSE(dba->remove_vertex(va));
|
||||
dba->advance_command();
|
||||
for (auto &vertex : vertices) vertex.Reconstruct();
|
||||
|
||||
EXPECT_EQ(CountVertices(*dba), 2);
|
||||
EXPECT_EQ(CountEdges(*dba), 1);
|
||||
EXPECT_EQ(Count(dba->vertices()), 2);
|
||||
EXPECT_EQ(Count(dba->edges()), 1);
|
||||
for (auto va : dba->vertices()) {
|
||||
EXPECT_FALSE(dba->remove_vertex(va));
|
||||
dba->detach_remove_vertex(va);
|
||||
break;
|
||||
}
|
||||
EXPECT_EQ(Count(dba->vertices(true)), 1);
|
||||
EXPECT_EQ(Count(dba->vertices()), 2);
|
||||
dba->advance_command();
|
||||
for (auto &vertex : vertices) vertex.Reconstruct();
|
||||
|
||||
EXPECT_EQ(CountVertices(*dba), 1);
|
||||
EXPECT_EQ(CountEdges(*dba), 0);
|
||||
EXPECT_EQ(Count(dba->vertices()), 1);
|
||||
EXPECT_EQ(Count(dba->edges()), 0);
|
||||
|
||||
// remove the last vertex, it has no connections
|
||||
// so that should work
|
||||
for (auto va : dba->vertices()) EXPECT_TRUE(dba->remove_vertex(va));
|
||||
dba->advance_command();
|
||||
|
||||
EXPECT_EQ(CountVertices(*dba), 0);
|
||||
EXPECT_EQ(CountEdges(*dba), 0);
|
||||
EXPECT_EQ(Count(dba->vertices()), 0);
|
||||
EXPECT_EQ(Count(dba->edges()), 0);
|
||||
}
|
||||
|
||||
TEST(GraphDbAccessorTest, DetachRemoveVertexMultiple) {
|
||||
@ -241,30 +258,30 @@ TEST(GraphDbAccessorTest, DetachRemoveVertexMultiple) {
|
||||
dba->advance_command();
|
||||
for (auto &vertex : vertices) vertex.Reconstruct();
|
||||
|
||||
EXPECT_EQ(CountVertices(*dba), N);
|
||||
EXPECT_EQ(CountEdges(*dba), N * N);
|
||||
EXPECT_EQ(Count(dba->vertices()), N);
|
||||
EXPECT_EQ(Count(dba->edges()), N * N);
|
||||
|
||||
// detach delete one edge
|
||||
dba->detach_remove_vertex(vertices[0]);
|
||||
dba->advance_command();
|
||||
for (auto &vertex : vertices) vertex.Reconstruct();
|
||||
EXPECT_EQ(CountVertices(*dba), N - 1);
|
||||
EXPECT_EQ(CountEdges(*dba), (N - 1) * (N - 1));
|
||||
EXPECT_EQ(Count(dba->vertices()), N - 1);
|
||||
EXPECT_EQ(Count(dba->edges()), (N - 1) * (N - 1));
|
||||
|
||||
// detach delete two neighboring edges
|
||||
dba->detach_remove_vertex(vertices[1]);
|
||||
dba->detach_remove_vertex(vertices[2]);
|
||||
dba->advance_command();
|
||||
for (auto &vertex : vertices) vertex.Reconstruct();
|
||||
EXPECT_EQ(CountVertices(*dba), N - 3);
|
||||
EXPECT_EQ(CountEdges(*dba), (N - 3) * (N - 3));
|
||||
EXPECT_EQ(Count(dba->vertices()), N - 3);
|
||||
EXPECT_EQ(Count(dba->edges()), (N - 3) * (N - 3));
|
||||
|
||||
// detach delete everything, buwahahahaha
|
||||
for (int l = 3; l < N; ++l) dba->detach_remove_vertex(vertices[l]);
|
||||
dba->advance_command();
|
||||
for (auto &vertex : vertices) vertex.Reconstruct();
|
||||
EXPECT_EQ(CountVertices(*dba), 0);
|
||||
EXPECT_EQ(CountEdges(*dba), 0);
|
||||
EXPECT_EQ(Count(dba->vertices()), 0);
|
||||
EXPECT_EQ(Count(dba->edges()), 0);
|
||||
}
|
||||
|
||||
TEST(GraphDbAccessorTest, Labels) {
|
||||
|
126
tests/unit/graph_db_accessor_index_api.cpp
Normal file
126
tests/unit/graph_db_accessor_index_api.cpp
Normal file
@ -0,0 +1,126 @@
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "data_structures/ptr_int.hpp"
|
||||
#include "database/graph_db_accessor.hpp"
|
||||
#include "dbms/dbms.hpp"
|
||||
|
||||
using testing::UnorderedElementsAreArray;
|
||||
|
||||
template <typename TIterable>
|
||||
auto Count(TIterable iterable) {
|
||||
return std::distance(iterable.begin(), iterable.end());
|
||||
}
|
||||
|
||||
TEST(GraphDbAccessor, VertexCount) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto lab1 = dba->label("lab1");
|
||||
auto lab2 = dba->label("lab2");
|
||||
|
||||
EXPECT_EQ(dba->vertices_count(lab1), 0);
|
||||
EXPECT_EQ(dba->vertices_count(lab2), 0);
|
||||
EXPECT_EQ(dba->vertices_count(), 0);
|
||||
for (int i = 0; i < 11; ++i) dba->insert_vertex().add_label(lab1);
|
||||
for (int i = 0; i < 17; ++i) dba->insert_vertex().add_label(lab2);
|
||||
// even though xxx_count functions in GraphDbAccessor can over-estaimate
|
||||
// in this situation they should be exact (nothing was ever deleted)
|
||||
EXPECT_EQ(dba->vertices_count(lab1), 11);
|
||||
EXPECT_EQ(dba->vertices_count(lab2), 17);
|
||||
EXPECT_EQ(dba->vertices_count(), 28);
|
||||
}
|
||||
|
||||
TEST(GraphDbAccessor, EdgeCount) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto t1 = dba->edge_type("t1");
|
||||
auto t2 = dba->edge_type("t2");
|
||||
|
||||
EXPECT_EQ(dba->edges_count(t1), 0);
|
||||
EXPECT_EQ(dba->edges_count(t2), 0);
|
||||
EXPECT_EQ(dba->edges_count(), 0);
|
||||
auto v1 = dba->insert_vertex();
|
||||
auto v2 = dba->insert_vertex();
|
||||
for (int i = 0; i < 11; ++i) dba->insert_edge(v1, v2, t1);
|
||||
for (int i = 0; i < 17; ++i) dba->insert_edge(v1, v2, t2);
|
||||
// even though xxx_count functions in GraphDbAccessor can over-estaimate
|
||||
// in this situation they should be exact (nothing was ever deleted)
|
||||
EXPECT_EQ(dba->edges_count(t1), 11);
|
||||
EXPECT_EQ(dba->edges_count(t2), 17);
|
||||
EXPECT_EQ(dba->edges_count(), 28);
|
||||
}
|
||||
|
||||
TEST(GraphDbAccessor, VisibilityAfterInsertion) {
|
||||
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto v1 = dba->insert_vertex();
|
||||
auto v2 = dba->insert_vertex();
|
||||
auto lab1 = dba->label("lab1");
|
||||
auto lab2 = dba->label("lab2");
|
||||
v1.add_label(lab1);
|
||||
auto type1 = dba->edge_type("type1");
|
||||
auto type2 = dba->edge_type("type2");
|
||||
dba->insert_edge(v1, v2, type1);
|
||||
|
||||
EXPECT_EQ(Count(dba->vertices(lab1)), 0);
|
||||
EXPECT_EQ(Count(dba->vertices(lab1, true)), 1);
|
||||
EXPECT_EQ(Count(dba->vertices(lab2)), 0);
|
||||
EXPECT_EQ(Count(dba->vertices(lab2, true)), 0);
|
||||
EXPECT_EQ(Count(dba->edges(type1)), 0);
|
||||
EXPECT_EQ(Count(dba->edges(type1, true)), 1);
|
||||
EXPECT_EQ(Count(dba->edges(type2)), 0);
|
||||
EXPECT_EQ(Count(dba->edges(type2, true)), 0);
|
||||
|
||||
dba->advance_command();
|
||||
|
||||
EXPECT_EQ(Count(dba->vertices(lab1)), 1);
|
||||
EXPECT_EQ(Count(dba->vertices(lab1, true)), 1);
|
||||
EXPECT_EQ(Count(dba->vertices(lab2)), 0);
|
||||
EXPECT_EQ(Count(dba->vertices(lab2, true)), 0);
|
||||
EXPECT_EQ(Count(dba->edges(type1)), 1);
|
||||
EXPECT_EQ(Count(dba->edges(type1, true)), 1);
|
||||
EXPECT_EQ(Count(dba->edges(type2)), 0);
|
||||
EXPECT_EQ(Count(dba->edges(type2, true)), 0);
|
||||
}
|
||||
|
||||
TEST(GraphDbAccessor, VisibilityAfterDeletion) {
|
||||
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto lab = dba->label("lab");
|
||||
for (int i = 0; i < 5; ++i)
|
||||
dba->insert_vertex().add_label(lab);
|
||||
dba->advance_command();
|
||||
auto type = dba->edge_type("type");
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
auto vertices_it = dba->vertices().begin();
|
||||
dba->insert_edge(*vertices_it++, *vertices_it, type);
|
||||
}
|
||||
dba->advance_command();
|
||||
|
||||
EXPECT_EQ(Count(dba->vertices(lab)), 5);
|
||||
EXPECT_EQ(Count(dba->vertices(lab, true)), 5);
|
||||
EXPECT_EQ(Count(dba->edges(type)), 3);
|
||||
EXPECT_EQ(Count(dba->edges(type, true)), 3);
|
||||
|
||||
// delete two edges
|
||||
auto edges_it = dba->edges().begin();
|
||||
for (int k = 0; k < 2; ++k)
|
||||
dba->remove_edge(*edges_it++);
|
||||
EXPECT_EQ(Count(dba->edges(type)), 3);
|
||||
EXPECT_EQ(Count(dba->edges(type, true)), 1);
|
||||
dba->advance_command();
|
||||
EXPECT_EQ(Count(dba->edges(type)), 1);
|
||||
EXPECT_EQ(Count(dba->edges(type, true)), 1);
|
||||
|
||||
// detach-delete 2 vertices
|
||||
auto vertices_it = dba->vertices().begin();
|
||||
for (int k = 0; k < 2; ++k)
|
||||
dba->detach_remove_vertex(*vertices_it++);
|
||||
EXPECT_EQ(Count(dba->vertices(lab)), 5);
|
||||
EXPECT_EQ(Count(dba->vertices(lab, true)), 3);
|
||||
dba->advance_command();
|
||||
EXPECT_EQ(Count(dba->vertices(lab)), 3);
|
||||
EXPECT_EQ(Count(dba->vertices(lab, true)), 3);
|
||||
}
|
Loading…
Reference in New Issue
Block a user