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);
|
this->db_.labels_index_.Update(label, vertex_accessor.vlist_, vertex);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t GraphDbAccessor::vertices_count(const GraphDbTypes::Label &label) {
|
size_t GraphDbAccessor::vertices_count() const {
|
||||||
return this->db_.labels_index_.Count(label);
|
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) {
|
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);
|
this->db_.edge_types_index_.Update(edge_type, edge_accessor.vlist_, edge);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t GraphDbAccessor::edges_count(const GraphDbTypes::EdgeType &edge_type) {
|
size_t GraphDbAccessor::edges_count() const {
|
||||||
return this->db_.edge_types_index_.Count(edge_type);
|
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
|
* Returns iterable over accessors to all the vertices in the graph
|
||||||
* visible to the current transaction.
|
* 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
|
// wrap version lists into accessors, which will look for visible versions
|
||||||
auto accessors =
|
auto accessors =
|
||||||
iter::imap([this](auto vlist) { return VertexAccessor(*vlist, *this); },
|
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
|
// filter out the accessors not visible to the current transaction
|
||||||
return iter::filter(
|
return iter::filter(
|
||||||
[this](const VertexAccessor &accessor) {
|
[this, current_state](const VertexAccessor &accessor) {
|
||||||
return accessor.old_ != nullptr;
|
return (accessor.old_ &&
|
||||||
|
!(current_state &&
|
||||||
|
accessor.old_->is_deleted_by(*transaction_))) ||
|
||||||
|
(current_state && accessor.new_ &&
|
||||||
|
!accessor.new_->is_deleted_by(*transaction_));
|
||||||
},
|
},
|
||||||
std::move(accessors));
|
std::move(accessors));
|
||||||
}
|
}
|
||||||
@ -97,12 +106,18 @@ class GraphDbAccessor {
|
|||||||
* Return VertexAccessors which contain the current label for the current
|
* Return VertexAccessors which contain the current label for the current
|
||||||
* transaction visibilty.
|
* transaction visibilty.
|
||||||
* @param label - label for which to return VertexAccessors
|
* @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
|
* @return iterable collection
|
||||||
*/
|
*/
|
||||||
auto vertices(const GraphDbTypes::Label &label) {
|
auto vertices(const GraphDbTypes::Label &label, bool current_state = false) {
|
||||||
return iter::imap(
|
return iter::imap(
|
||||||
[this](auto vlist) { return VertexAccessor(*vlist, *this); },
|
[this, current_state](auto vlist) {
|
||||||
db_.labels_index_.GetVlists(label, *transaction_));
|
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
|
* Returns iterable over accessors to all the edges in the graph
|
||||||
* visible to the current transaction.
|
* 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
|
// wrap version lists into accessors, which will look for visible versions
|
||||||
auto accessors =
|
auto accessors =
|
||||||
iter::imap([this](auto vlist) { return EdgeAccessor(*vlist, *this); },
|
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
|
// filter out the accessors not visible to the current transaction
|
||||||
return iter::filter(
|
return iter::filter(
|
||||||
[this](const EdgeAccessor &accessor) {
|
[this, current_state](const EdgeAccessor &accessor) {
|
||||||
return accessor.old_ != nullptr;
|
return (accessor.old_ &&
|
||||||
|
!(current_state &&
|
||||||
|
accessor.old_->is_deleted_by(*transaction_))) ||
|
||||||
|
(current_state && accessor.new_ &&
|
||||||
|
!accessor.new_->is_deleted_by(*transaction_));
|
||||||
},
|
},
|
||||||
std::move(accessors));
|
std::move(accessors));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return EdgeAccessors which contain the edge_type for the current
|
* 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 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
|
* @return iterable collection
|
||||||
*/
|
*/
|
||||||
auto edges(const GraphDbTypes::EdgeType &edge_type) {
|
auto edges(const GraphDbTypes::EdgeType &edge_type,
|
||||||
return iter::imap(
|
bool current_state = false) {
|
||||||
[this](auto vlist) { return EdgeAccessor(*vlist, *this); },
|
return iter::imap([this, current_state](
|
||||||
db_.edge_types_index_.GetVlists(edge_type, *transaction_));
|
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 EdgeAccessor &edge_accessor,
|
||||||
const Edge *edge);
|
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.
|
* Return approximate number of vertices under indexes with the given label.
|
||||||
* Note that this is always an over-estimate and never an under-estimate.
|
* Note that this is always an over-estimate and never an under-estimate.
|
||||||
* @param label - label to check for
|
* @param label - label to check for
|
||||||
* @return number of vertices with the given label
|
* @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.
|
* 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
|
* @param edge_type - edge_type to check for
|
||||||
* @return number of edges with the given edge_type
|
* @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.
|
* Obtains the Label for the label's name.
|
||||||
@ -258,7 +300,7 @@ class GraphDbAccessor {
|
|||||||
*/
|
*/
|
||||||
template <typename TRecord>
|
template <typename TRecord>
|
||||||
bool Reconstruct(RecordAccessor<TRecord> &accessor) {
|
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.new_);
|
||||||
accessor.current_ = accessor.old_ ? accessor.old_ : accessor.new_;
|
accessor.current_ = accessor.old_ ? accessor.old_ : accessor.new_;
|
||||||
return accessor.old_ != nullptr || accessor.new_ != nullptr;
|
return accessor.old_ != nullptr || accessor.new_ != nullptr;
|
||||||
|
@ -44,19 +44,40 @@ class KeyIndex {
|
|||||||
* still have that label visible in this transaction.
|
* still have that label visible in this transaction.
|
||||||
* @param key - key to query.
|
* @param key - key to query.
|
||||||
* @param t - current transaction, which determines visibility.
|
* @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
|
* @return iterable collection of vlists records<TRecord> with the requested
|
||||||
* TKey.
|
* 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);
|
auto index = GetKeyStorage(key);
|
||||||
mvcc::VersionList<TRecord> *prev = nullptr;
|
mvcc::VersionList<TRecord> *prev = nullptr;
|
||||||
auto filtered = iter::filter(
|
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;
|
if (entry.vlist_ == prev) return false;
|
||||||
auto version = entry.vlist_->find(t);
|
|
||||||
prev = entry.vlist_;
|
prev = entry.vlist_;
|
||||||
if (version == nullptr) return false;
|
// TODO when refactoring MVCC reconsider the return-value-arg idiom here
|
||||||
return Exists(key, version);
|
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());
|
index->access());
|
||||||
return iter::imap([this](auto entry) { return entry.vlist_; },
|
return iter::imap([this](auto entry) { return entry.vlist_; },
|
||||||
|
@ -178,7 +178,7 @@ class VersionList {
|
|||||||
*
|
*
|
||||||
* @param t The transaction
|
* @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
|
// assume that the sought old record is further down the list
|
||||||
// from new record, so that if we found old we can stop looking
|
// from new record, so that if we found old we can stop looking
|
||||||
new_ref = nullptr;
|
new_ref = nullptr;
|
||||||
|
@ -188,12 +188,8 @@ std::unique_ptr<Cursor> ScanAll::MakeCursor(GraphDbAccessor &db) {
|
|||||||
ScanAll::ScanAllCursor::ScanAllCursor(const ScanAll &self, GraphDbAccessor &db)
|
ScanAll::ScanAllCursor::ScanAllCursor(const ScanAll &self, GraphDbAccessor &db)
|
||||||
: self_(self),
|
: self_(self),
|
||||||
input_cursor_(self.input_->MakeCursor(db)),
|
input_cursor_(self.input_->MakeCursor(db)),
|
||||||
// TODO change to db.vertices(self.graph_view_ == GraphView::NEW)
|
vertices_(db.vertices(self.graph_view_ == GraphView::NEW)),
|
||||||
// once this GraphDbAccessor API is available
|
vertices_it_(vertices_.end()) {}
|
||||||
vertices_(db.vertices()),
|
|
||||||
vertices_it_(vertices_.end()) {
|
|
||||||
if (self.graph_view_ == GraphView::NEW) throw utils::NotYetImplemented();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ScanAll::ScanAllCursor::Pull(Frame &frame,
|
bool ScanAll::ScanAllCursor::Pull(Frame &frame,
|
||||||
const SymbolTable &symbol_table) {
|
const SymbolTable &symbol_table) {
|
||||||
|
@ -2,66 +2,46 @@
|
|||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
#include "data_structures/ptr_int.hpp"
|
#include "data_structures/ptr_int.hpp"
|
||||||
#include "database/graph_db_accessor.hpp"
|
|
||||||
#include "database/graph_db_datatypes.hpp"
|
#include "database/graph_db_datatypes.hpp"
|
||||||
|
#include "database/graph_db_accessor.hpp"
|
||||||
#include "dbms/dbms.hpp"
|
#include "dbms/dbms.hpp"
|
||||||
#include "storage/vertex.hpp"
|
#include "storage/vertex.hpp"
|
||||||
|
|
||||||
using testing::UnorderedElementsAreArray;
|
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 index does it insert everything uniquely
|
||||||
TEST(LabelsIndex, UniqueInsert) {
|
TEST(LabelsIndex, UniqueInsert) {
|
||||||
KeyIndex<GraphDbTypes::Label, Vertex> index;
|
KeyIndex<GraphDbTypes::Label, Vertex> index;
|
||||||
Dbms dbms;
|
Dbms dbms;
|
||||||
auto access = dbms.active();
|
auto dba = dbms.active();
|
||||||
tx::Engine engine;
|
tx::Engine engine;
|
||||||
auto t1 = engine.begin();
|
auto t1 = engine.begin();
|
||||||
mvcc::VersionList<Vertex> vlist(*t1);
|
mvcc::VersionList<Vertex> vlist(*t1);
|
||||||
t1->commit();
|
t1->commit();
|
||||||
auto t2 = engine.begin();
|
auto t2 = engine.begin();
|
||||||
|
|
||||||
vlist.find(*t2)->labels_.push_back(access->label("1"));
|
vlist.find(*t2)->labels_.push_back(dba->label("1"));
|
||||||
index.Update(access->label("1"), &vlist, vlist.find(*t2));
|
index.Update(dba->label("1"), &vlist, vlist.find(*t2));
|
||||||
// Try multiple inserts
|
// 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"));
|
vlist.find(*t2)->labels_.push_back(dba->label("2"));
|
||||||
index.Update(access->label("2"), &vlist, vlist.find(*t2));
|
index.Update(dba->label("2"), &vlist, vlist.find(*t2));
|
||||||
|
|
||||||
vlist.find(*t2)->labels_.push_back(access->label("3"));
|
vlist.find(*t2)->labels_.push_back(dba->label("3"));
|
||||||
index.Update(access->label("3"), &vlist, vlist.find(*t2));
|
index.Update(dba->label("3"), &vlist, vlist.find(*t2));
|
||||||
t2->commit();
|
t2->commit();
|
||||||
|
|
||||||
EXPECT_EQ(index.Count(access->label("1")), 1);
|
EXPECT_EQ(index.Count(dba->label("1")), 1);
|
||||||
EXPECT_EQ(index.Count(access->label("2")), 1);
|
EXPECT_EQ(index.Count(dba->label("2")), 1);
|
||||||
EXPECT_EQ(index.Count(access->label("3")), 1);
|
EXPECT_EQ(index.Count(dba->label("3")), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if index filters duplicates.
|
// Check if index filters duplicates.
|
||||||
TEST(LabelsIndex, UniqueFilter) {
|
TEST(LabelsIndex, UniqueFilter) {
|
||||||
KeyIndex<GraphDbTypes::Label, Vertex> index;
|
KeyIndex<GraphDbTypes::Label, Vertex> index;
|
||||||
Dbms dbms;
|
Dbms dbms;
|
||||||
auto access = dbms.active();
|
auto dba = dbms.active();
|
||||||
tx::Engine engine;
|
tx::Engine engine;
|
||||||
|
|
||||||
auto t1 = engine.begin();
|
auto t1 = engine.begin();
|
||||||
@ -70,10 +50,10 @@ TEST(LabelsIndex, UniqueFilter) {
|
|||||||
t1->engine.advance(
|
t1->engine.advance(
|
||||||
t1->id); // advance command so we can see our inserted version
|
t1->id); // advance command so we can see our inserted version
|
||||||
auto r1v1 = vlist1.find(*t1);
|
auto r1v1 = vlist1.find(*t1);
|
||||||
auto r1v2 = vlist1.find(*t1);
|
auto r1v2 = vlist2.find(*t1);
|
||||||
EXPECT_NE(vlist1.find(*t1), nullptr);
|
EXPECT_NE(vlist1.find(*t1), nullptr);
|
||||||
|
|
||||||
auto label1 = access->label("1");
|
auto label1 = dba->label("1");
|
||||||
vlist1.find(*t1)->labels_.push_back(label1);
|
vlist1.find(*t1)->labels_.push_back(label1);
|
||||||
vlist2.find(*t1)->labels_.push_back(label1);
|
vlist2.find(*t1)->labels_.push_back(label1);
|
||||||
index.Update(label1, &vlist1, r1v1);
|
index.Update(label1, &vlist1, r1v1);
|
||||||
@ -140,10 +120,10 @@ TEST(LabelsIndex, Refresh) {
|
|||||||
// Transaction hasn't ended and so the vertex is not visible.
|
// Transaction hasn't ended and so the vertex is not visible.
|
||||||
TEST(LabelsIndexDb, AddGetZeroLabels) {
|
TEST(LabelsIndexDb, AddGetZeroLabels) {
|
||||||
Dbms dbms;
|
Dbms dbms;
|
||||||
auto accessor = dbms.active();
|
auto dba = dbms.active();
|
||||||
auto vertex = accessor->insert_vertex();
|
auto vertex = dba->insert_vertex();
|
||||||
vertex.add_label(accessor->label("test"));
|
vertex.add_label(dba->label("test"));
|
||||||
auto collection = accessor->vertices(accessor->label("test"));
|
auto collection = dba->vertices(dba->label("test"));
|
||||||
std::vector<VertexAccessor> collection_vector(collection.begin(),
|
std::vector<VertexAccessor> collection_vector(collection.begin(),
|
||||||
collection.end());
|
collection.end());
|
||||||
EXPECT_EQ(collection_vector.size(), (size_t)0);
|
EXPECT_EQ(collection_vector.size(), (size_t)0);
|
||||||
@ -154,61 +134,61 @@ TEST(LabelsIndexDb, AddGetZeroLabels) {
|
|||||||
TEST(LabelsIndexDb, AddGetRemoveLabel) {
|
TEST(LabelsIndexDb, AddGetRemoveLabel) {
|
||||||
Dbms dbms;
|
Dbms dbms;
|
||||||
{
|
{
|
||||||
auto accessor = dbms.active();
|
auto dba = dbms.active();
|
||||||
|
|
||||||
auto vertex1 = accessor->insert_vertex();
|
auto vertex1 = dba->insert_vertex();
|
||||||
vertex1.add_label(accessor->label("test"));
|
vertex1.add_label(dba->label("test"));
|
||||||
|
|
||||||
auto vertex2 = accessor->insert_vertex();
|
auto vertex2 = dba->insert_vertex();
|
||||||
vertex2.add_label(accessor->label("test2"));
|
vertex2.add_label(dba->label("test2"));
|
||||||
|
|
||||||
auto vertex3 = accessor->insert_vertex();
|
auto vertex3 = dba->insert_vertex();
|
||||||
vertex3.add_label(accessor->label("test"));
|
vertex3.add_label(dba->label("test"));
|
||||||
|
|
||||||
accessor->commit();
|
dba->commit();
|
||||||
} // Finish transaction.
|
} // 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());
|
std::vector<VertexAccessor> collection(filtered.begin(), filtered.end());
|
||||||
auto vertices = accessor->vertices();
|
auto vertices = dba->vertices();
|
||||||
|
|
||||||
std::vector<VertexAccessor> expected_collection;
|
std::vector<VertexAccessor> expected_collection;
|
||||||
for (auto vertex : vertices) {
|
for (auto vertex : vertices) {
|
||||||
if (vertex.has_label(accessor->label("test"))) {
|
if (vertex.has_label(dba->label("test"))) {
|
||||||
expected_collection.push_back(vertex);
|
expected_collection.push_back(vertex);
|
||||||
} else {
|
} 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_EQ(expected_collection.size(), collection.size());
|
||||||
EXPECT_TRUE(collection[0].has_label(accessor->label("test")));
|
EXPECT_TRUE(collection[0].has_label(dba->label("test")));
|
||||||
EXPECT_TRUE(collection[1].has_label(accessor->label("test")));
|
EXPECT_TRUE(collection[1].has_label(dba->label("test")));
|
||||||
EXPECT_FALSE(collection[0].has_label(accessor->label("test2")));
|
EXPECT_FALSE(collection[0].has_label(dba->label("test2")));
|
||||||
EXPECT_FALSE(collection[1].has_label(accessor->label("test2")));
|
EXPECT_FALSE(collection[1].has_label(dba->label("test2")));
|
||||||
accessor->remove_vertex(collection[0]); // Remove from database and test if
|
dba->remove_vertex(collection[0]); // Remove from database and test if
|
||||||
// index won't return it.
|
// index won't return it.
|
||||||
|
|
||||||
// Remove label from the vertex and add new label.
|
// Remove label from the vertex and add new label.
|
||||||
collection[1].remove_label(accessor->label("test"));
|
collection[1].remove_label(dba->label("test"));
|
||||||
collection[1].add_label(accessor->label("test2"));
|
collection[1].add_label(dba->label("test2"));
|
||||||
accessor->commit();
|
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());
|
std::vector<VertexAccessor> collection(filtered.begin(), filtered.end());
|
||||||
auto vertices = accessor->vertices();
|
auto vertices = dba->vertices();
|
||||||
|
|
||||||
std::vector<VertexAccessor> expected_collection;
|
std::vector<VertexAccessor> expected_collection;
|
||||||
for (auto vertex : vertices) {
|
for (auto vertex : vertices) {
|
||||||
if (vertex.has_label(accessor->label("test"))) {
|
if (vertex.has_label(dba->label("test"))) {
|
||||||
expected_collection.push_back(vertex);
|
expected_collection.push_back(vertex);
|
||||||
} else {
|
} 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) {
|
int main(int argc, char **argv) {
|
||||||
::testing::InitGoogleTest(&argc, argv);
|
::testing::InitGoogleTest(&argc, argv);
|
||||||
return RUN_ALL_TESTS();
|
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/edge_accessor.hpp"
|
||||||
#include "storage/vertex_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;
|
template <typename TIterable>
|
||||||
}
|
auto Count(TIterable iterable) {
|
||||||
|
return std::distance(iterable.begin(), iterable.end());
|
||||||
size_t CountEdges(GraphDbAccessor &db_accessor) {
|
|
||||||
size_t r_val = 0;
|
|
||||||
for ([[gnu::unused]] auto va : db_accessor.edges()) r_val++;
|
|
||||||
|
|
||||||
return r_val;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(GraphDbAccessorTest, DbmsCreateDefault) {
|
TEST(GraphDbAccessorTest, DbmsCreateDefault) {
|
||||||
@ -31,31 +23,37 @@ TEST(GraphDbAccessorTest, InsertVertex) {
|
|||||||
Dbms dbms;
|
Dbms dbms;
|
||||||
auto accessor = dbms.active();
|
auto accessor = dbms.active();
|
||||||
|
|
||||||
EXPECT_EQ(CountVertices(*accessor), 0);
|
EXPECT_EQ(Count(accessor->vertices()), 0);
|
||||||
|
|
||||||
accessor->insert_vertex();
|
accessor->insert_vertex();
|
||||||
|
EXPECT_EQ(Count(accessor->vertices()), 0);
|
||||||
|
EXPECT_EQ(Count(accessor->vertices(true)), 1);
|
||||||
accessor->advance_command();
|
accessor->advance_command();
|
||||||
EXPECT_EQ(CountVertices(*accessor), 1);
|
EXPECT_EQ(Count(accessor->vertices()), 1);
|
||||||
|
|
||||||
accessor->insert_vertex();
|
accessor->insert_vertex();
|
||||||
|
EXPECT_EQ(Count(accessor->vertices()), 1);
|
||||||
|
EXPECT_EQ(Count(accessor->vertices(true)), 2);
|
||||||
accessor->advance_command();
|
accessor->advance_command();
|
||||||
EXPECT_EQ(CountVertices(*accessor), 2);
|
EXPECT_EQ(Count(accessor->vertices()), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(GraphDbAccessorTest, RemoveVertexSameTransaction) {
|
TEST(GraphDbAccessorTest, RemoveVertexSameTransaction) {
|
||||||
Dbms dbms;
|
Dbms dbms;
|
||||||
auto accessor = dbms.active();
|
auto accessor = dbms.active();
|
||||||
|
|
||||||
EXPECT_EQ(CountVertices(*accessor), 0);
|
EXPECT_EQ(Count(accessor->vertices()), 0);
|
||||||
|
|
||||||
auto va1 = accessor->insert_vertex();
|
auto va1 = accessor->insert_vertex();
|
||||||
accessor->advance_command();
|
accessor->advance_command();
|
||||||
EXPECT_EQ(CountVertices(*accessor), 1);
|
EXPECT_EQ(Count(accessor->vertices()), 1);
|
||||||
|
|
||||||
EXPECT_TRUE(accessor->remove_vertex(va1));
|
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();
|
accessor->advance_command();
|
||||||
EXPECT_EQ(CountVertices(*accessor), 0);
|
EXPECT_EQ(Count(accessor->vertices()), 0);
|
||||||
|
EXPECT_EQ(Count(accessor->vertices(true)), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(GraphDbAccessorTest, RemoveVertexDifferentTransaction) {
|
TEST(GraphDbAccessorTest, RemoveVertexDifferentTransaction) {
|
||||||
@ -68,14 +66,16 @@ TEST(GraphDbAccessorTest, RemoveVertexDifferentTransaction) {
|
|||||||
|
|
||||||
// second transaction checks that it sees it, and deletes it
|
// second transaction checks that it sees it, and deletes it
|
||||||
auto accessor2 = dbms.active();
|
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())
|
for (auto vertex_accessor : accessor2->vertices())
|
||||||
accessor2->remove_vertex(vertex_accessor);
|
accessor2->remove_vertex(vertex_accessor);
|
||||||
accessor2->commit();
|
accessor2->commit();
|
||||||
|
|
||||||
// third transaction checks that it does not see the vertex
|
// third transaction checks that it does not see the vertex
|
||||||
auto accessor3 = dbms.active();
|
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) {
|
TEST(GraphDbAccessorTest, InsertEdge) {
|
||||||
@ -92,8 +92,11 @@ TEST(GraphDbAccessorTest, InsertEdge) {
|
|||||||
|
|
||||||
// setup (v1) - [:likes] -> (v2)
|
// setup (v1) - [:likes] -> (v2)
|
||||||
dba->insert_edge(va1, va2, dba->edge_type("likes"));
|
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();
|
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(va1.out().begin()->to(), va2);
|
||||||
EXPECT_EQ(va2.in().begin()->from(), va1);
|
EXPECT_EQ(va2.in().begin()->from(), va1);
|
||||||
EXPECT_EQ(va1.in_degree(), 0);
|
EXPECT_EQ(va1.in_degree(), 0);
|
||||||
@ -104,8 +107,10 @@ TEST(GraphDbAccessorTest, InsertEdge) {
|
|||||||
// setup (v1) - [:likes] -> (v2) <- [:hates] - (v3)
|
// setup (v1) - [:likes] -> (v2) <- [:hates] - (v3)
|
||||||
auto va3 = dba->insert_vertex();
|
auto va3 = dba->insert_vertex();
|
||||||
dba->insert_edge(va3, va2, dba->edge_type("hates"));
|
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();
|
dba->advance_command();
|
||||||
EXPECT_EQ(CountEdges(*dba), 2);
|
EXPECT_EQ(Count(dba->edges()), 2);
|
||||||
EXPECT_EQ(va3.out().begin()->to(), va2);
|
EXPECT_EQ(va3.out().begin()->to(), va2);
|
||||||
EXPECT_EQ(va1.in_degree(), 0);
|
EXPECT_EQ(va1.in_degree(), 0);
|
||||||
EXPECT_EQ(va1.out_degree(), 1);
|
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(va1, va2, dba->edge_type("likes"));
|
||||||
dba->insert_edge(va3, va2, dba->edge_type("hates"));
|
dba->insert_edge(va3, va2, dba->edge_type("hates"));
|
||||||
dba->advance_command();
|
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
|
// remove all [:hates] edges
|
||||||
EXPECT_EQ(CountEdges(*dba), 2);
|
|
||||||
for (auto edge : dba->edges())
|
for (auto edge : dba->edges())
|
||||||
if (edge.edge_type() == dba->edge_type("hates")) dba->remove_edge(edge);
|
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)
|
// current state: (v1) - [:likes] -> (v2), (v3)
|
||||||
dba->advance_command();
|
dba->advance_command();
|
||||||
EXPECT_EQ(CountEdges(*dba), 1);
|
EXPECT_EQ(Count(dba->edges()), 1);
|
||||||
EXPECT_EQ(CountVertices(*dba), 3);
|
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()) {
|
for (auto edge : dba->edges()) {
|
||||||
EXPECT_EQ(edge.edge_type(), dba->edge_type("likes"));
|
EXPECT_EQ(edge.edge_type(), dba->edge_type("likes"));
|
||||||
auto v1 = edge.from();
|
auto v1 = edge.from();
|
||||||
@ -175,50 +184,58 @@ TEST(GraphDbAccessorTest, DetachRemoveVertex) {
|
|||||||
for (auto &vertex : vertices) vertex.Reconstruct();
|
for (auto &vertex : vertices) vertex.Reconstruct();
|
||||||
|
|
||||||
// ensure that plain remove does NOT work
|
// ensure that plain remove does NOT work
|
||||||
EXPECT_EQ(CountVertices(*dba), 4);
|
EXPECT_EQ(Count(dba->vertices()), 4);
|
||||||
EXPECT_EQ(CountEdges(*dba), 3);
|
EXPECT_EQ(Count(dba->edges()), 3);
|
||||||
EXPECT_FALSE(dba->remove_vertex(vertices[0]));
|
EXPECT_FALSE(dba->remove_vertex(vertices[0]));
|
||||||
EXPECT_FALSE(dba->remove_vertex(vertices[1]));
|
EXPECT_FALSE(dba->remove_vertex(vertices[1]));
|
||||||
EXPECT_FALSE(dba->remove_vertex(vertices[2]));
|
EXPECT_FALSE(dba->remove_vertex(vertices[2]));
|
||||||
EXPECT_EQ(CountVertices(*dba), 4);
|
EXPECT_EQ(Count(dba->vertices()), 4);
|
||||||
EXPECT_EQ(CountEdges(*dba), 3);
|
EXPECT_EQ(Count(dba->edges()), 3);
|
||||||
|
|
||||||
dba->detach_remove_vertex(vertices[2]);
|
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();
|
dba->advance_command();
|
||||||
for (auto &vertex : vertices) vertex.Reconstruct();
|
for (auto &vertex : vertices) vertex.Reconstruct();
|
||||||
|
|
||||||
EXPECT_EQ(CountVertices(*dba), 3);
|
EXPECT_EQ(Count(dba->vertices()), 3);
|
||||||
EXPECT_EQ(CountEdges(*dba), 1);
|
EXPECT_EQ(Count(dba->edges()), 1);
|
||||||
EXPECT_TRUE(dba->remove_vertex(vertices[3]));
|
EXPECT_TRUE(dba->remove_vertex(vertices[3]));
|
||||||
|
EXPECT_EQ(Count(dba->vertices(true)), 2);
|
||||||
|
EXPECT_EQ(Count(dba->vertices()), 3);
|
||||||
dba->advance_command();
|
dba->advance_command();
|
||||||
for (auto &vertex : vertices) vertex.Reconstruct();
|
for (auto &vertex : vertices) vertex.Reconstruct();
|
||||||
|
|
||||||
EXPECT_EQ(CountVertices(*dba), 2);
|
EXPECT_EQ(Count(dba->vertices()), 2);
|
||||||
EXPECT_EQ(CountEdges(*dba), 1);
|
EXPECT_EQ(Count(dba->edges()), 1);
|
||||||
for (auto va : dba->vertices()) EXPECT_FALSE(dba->remove_vertex(va));
|
for (auto va : dba->vertices()) EXPECT_FALSE(dba->remove_vertex(va));
|
||||||
dba->advance_command();
|
dba->advance_command();
|
||||||
for (auto &vertex : vertices) vertex.Reconstruct();
|
for (auto &vertex : vertices) vertex.Reconstruct();
|
||||||
|
|
||||||
EXPECT_EQ(CountVertices(*dba), 2);
|
EXPECT_EQ(Count(dba->vertices()), 2);
|
||||||
EXPECT_EQ(CountEdges(*dba), 1);
|
EXPECT_EQ(Count(dba->edges()), 1);
|
||||||
for (auto va : dba->vertices()) {
|
for (auto va : dba->vertices()) {
|
||||||
EXPECT_FALSE(dba->remove_vertex(va));
|
EXPECT_FALSE(dba->remove_vertex(va));
|
||||||
dba->detach_remove_vertex(va);
|
dba->detach_remove_vertex(va);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
EXPECT_EQ(Count(dba->vertices(true)), 1);
|
||||||
|
EXPECT_EQ(Count(dba->vertices()), 2);
|
||||||
dba->advance_command();
|
dba->advance_command();
|
||||||
for (auto &vertex : vertices) vertex.Reconstruct();
|
for (auto &vertex : vertices) vertex.Reconstruct();
|
||||||
|
|
||||||
EXPECT_EQ(CountVertices(*dba), 1);
|
EXPECT_EQ(Count(dba->vertices()), 1);
|
||||||
EXPECT_EQ(CountEdges(*dba), 0);
|
EXPECT_EQ(Count(dba->edges()), 0);
|
||||||
|
|
||||||
// remove the last vertex, it has no connections
|
// remove the last vertex, it has no connections
|
||||||
// so that should work
|
// so that should work
|
||||||
for (auto va : dba->vertices()) EXPECT_TRUE(dba->remove_vertex(va));
|
for (auto va : dba->vertices()) EXPECT_TRUE(dba->remove_vertex(va));
|
||||||
dba->advance_command();
|
dba->advance_command();
|
||||||
|
|
||||||
EXPECT_EQ(CountVertices(*dba), 0);
|
EXPECT_EQ(Count(dba->vertices()), 0);
|
||||||
EXPECT_EQ(CountEdges(*dba), 0);
|
EXPECT_EQ(Count(dba->edges()), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(GraphDbAccessorTest, DetachRemoveVertexMultiple) {
|
TEST(GraphDbAccessorTest, DetachRemoveVertexMultiple) {
|
||||||
@ -241,30 +258,30 @@ TEST(GraphDbAccessorTest, DetachRemoveVertexMultiple) {
|
|||||||
dba->advance_command();
|
dba->advance_command();
|
||||||
for (auto &vertex : vertices) vertex.Reconstruct();
|
for (auto &vertex : vertices) vertex.Reconstruct();
|
||||||
|
|
||||||
EXPECT_EQ(CountVertices(*dba), N);
|
EXPECT_EQ(Count(dba->vertices()), N);
|
||||||
EXPECT_EQ(CountEdges(*dba), N * N);
|
EXPECT_EQ(Count(dba->edges()), N * N);
|
||||||
|
|
||||||
// detach delete one edge
|
// detach delete one edge
|
||||||
dba->detach_remove_vertex(vertices[0]);
|
dba->detach_remove_vertex(vertices[0]);
|
||||||
dba->advance_command();
|
dba->advance_command();
|
||||||
for (auto &vertex : vertices) vertex.Reconstruct();
|
for (auto &vertex : vertices) vertex.Reconstruct();
|
||||||
EXPECT_EQ(CountVertices(*dba), N - 1);
|
EXPECT_EQ(Count(dba->vertices()), N - 1);
|
||||||
EXPECT_EQ(CountEdges(*dba), (N - 1) * (N - 1));
|
EXPECT_EQ(Count(dba->edges()), (N - 1) * (N - 1));
|
||||||
|
|
||||||
// detach delete two neighboring edges
|
// detach delete two neighboring edges
|
||||||
dba->detach_remove_vertex(vertices[1]);
|
dba->detach_remove_vertex(vertices[1]);
|
||||||
dba->detach_remove_vertex(vertices[2]);
|
dba->detach_remove_vertex(vertices[2]);
|
||||||
dba->advance_command();
|
dba->advance_command();
|
||||||
for (auto &vertex : vertices) vertex.Reconstruct();
|
for (auto &vertex : vertices) vertex.Reconstruct();
|
||||||
EXPECT_EQ(CountVertices(*dba), N - 3);
|
EXPECT_EQ(Count(dba->vertices()), N - 3);
|
||||||
EXPECT_EQ(CountEdges(*dba), (N - 3) * (N - 3));
|
EXPECT_EQ(Count(dba->edges()), (N - 3) * (N - 3));
|
||||||
|
|
||||||
// detach delete everything, buwahahahaha
|
// detach delete everything, buwahahahaha
|
||||||
for (int l = 3; l < N; ++l) dba->detach_remove_vertex(vertices[l]);
|
for (int l = 3; l < N; ++l) dba->detach_remove_vertex(vertices[l]);
|
||||||
dba->advance_command();
|
dba->advance_command();
|
||||||
for (auto &vertex : vertices) vertex.Reconstruct();
|
for (auto &vertex : vertices) vertex.Reconstruct();
|
||||||
EXPECT_EQ(CountVertices(*dba), 0);
|
EXPECT_EQ(Count(dba->vertices()), 0);
|
||||||
EXPECT_EQ(CountEdges(*dba), 0);
|
EXPECT_EQ(Count(dba->edges()), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(GraphDbAccessorTest, Labels) {
|
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