Rework of index api. Remove implicit default value of current_state in graph_db_accessor.

Reviewers: buda, florijan

Reviewed By: buda, florijan

Subscribers: mislav.bradac, pullbot

Differential Revision: https://phabricator.memgraph.io/D392
This commit is contained in:
Dominik Gleich 2017-06-07 09:49:51 +02:00
parent 9acdc632e9
commit 141d9b3bb8
25 changed files with 398 additions and 199 deletions

View File

@ -241,6 +241,16 @@ class SkipList : private Lockable<lock_t> {
IteratorBase() = default;
IteratorBase(const IteratorBase &) = default;
const T &operator*() const {
debug_assert(node != nullptr, "Node is nullptr.");
return node->value();
}
const T *operator->() const {
debug_assert(node != nullptr, "Node is nullptr.");
return &node->value();
}
T &operator*() {
debug_assert(node != nullptr, "Node is nullptr.");
return node->value();
@ -284,9 +294,13 @@ class SkipList : private Lockable<lock_t> {
ConstIterator() = default;
ConstIterator(const ConstIterator &) = default;
const T &operator*() { return IteratorBase<ConstIterator>::operator*(); }
const T &operator*() const {
return IteratorBase<ConstIterator>::operator*();
}
const T *operator->() { return IteratorBase<ConstIterator>::operator->(); }
const T *operator->() const {
return IteratorBase<ConstIterator>::operator->();
}
operator const T &() { return IteratorBase<ConstIterator>::operator T &(); }
};

View File

@ -91,7 +91,7 @@ class GraphDbAccessor {
* deletions performed in the current transaction+command are not
* ignored).
*/
auto vertices(bool current_state = false) {
auto vertices(bool current_state) {
// wrap version lists into accessors, which will look for visible versions
auto accessors =
iter::imap([this](auto vlist) { return VertexAccessor(*vlist, *this); },
@ -119,7 +119,7 @@ class GraphDbAccessor {
* ignored).
* @return iterable collection
*/
auto vertices(const GraphDbTypes::Label &label, bool current_state = false) {
auto vertices(const GraphDbTypes::Label &label, bool current_state) {
return iter::imap(
[this, current_state](auto vlist) {
return VertexAccessor(*vlist, *this);
@ -139,8 +139,7 @@ class GraphDbAccessor {
* @return iterable collection
*/
auto vertices(const GraphDbTypes::Label &label,
const GraphDbTypes::Property &property,
bool current_state = false) {
const GraphDbTypes::Property &property, bool current_state) {
debug_assert(db_.label_property_index_.IndexExists(
LabelPropertyIndex::Key(label, property)),
"Label+property index doesn't exist.");
@ -151,6 +150,34 @@ class GraphDbAccessor {
*transaction_, current_state));
}
/**
* Return VertexAccessors which contain the current label + property, and
* those properties are equal to this 'value' for the given transaction
* visibility.
* @param label - label for which to return VertexAccessors
* @param property - property for which to return VertexAccessors
* @param value - property value 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,
const GraphDbTypes::Property &property,
const PropertyValue &value, bool current_state) {
debug_assert(db_.label_property_index_.IndexExists(
LabelPropertyIndex::Key(label, property)),
"Label+property index doesn't exist.");
debug_assert(value.type() != PropertyValue::Type::Null,
"Can't query index for propery value type null.");
return iter::imap([this, current_state](
auto vlist) { return VertexAccessor(*vlist, *this); },
db_.label_property_index_.GetVlists(
LabelPropertyIndex::Key(label, property), value,
*transaction_, current_state));
}
/**
* Creates a new Edge and returns an accessor to it.
*
@ -178,7 +205,7 @@ class GraphDbAccessor {
* deletions performed in the current transaction+command are not
* ignored).
*/
auto edges(bool current_state = false) {
auto edges(bool current_state) {
// wrap version lists into accessors, which will look for visible versions
auto accessors =
iter::imap([this](auto vlist) { return EdgeAccessor(*vlist, *this); },
@ -206,8 +233,7 @@ class GraphDbAccessor {
* ignored).
* @return iterable collection
*/
auto edges(const GraphDbTypes::EdgeType &edge_type,
bool current_state = false) {
auto edges(const GraphDbTypes::EdgeType &edge_type, bool current_state) {
return iter::imap([this, current_state](
auto vlist) { return EdgeAccessor(*vlist, *this); },
db_.edge_types_index_.GetVlists(edge_type, *transaction_,

View File

@ -2,16 +2,61 @@
#include "cppitertools/filter.hpp"
#include "cppitertools/imap.hpp"
#include "cppitertools/takewhile.hpp"
#include "data_structures/concurrent/concurrent_map.hpp"
#include "data_structures/concurrent/skiplist.hpp"
#include "mvcc/version_list.hpp"
#include "transactions/transaction.hpp"
namespace IndexUtils {
/**
* @brief - Wrap beginning iterator to iterable object. This provides us with
* begin and end iterator, and allows us to iterate from the iterator given in
* constructor till the end of the collection over which we are really
* iterating, i.e. it allows us to iterate over the suffix of some skiplist
* hence the name SkipListSuffix.
*/
template <class TIterator, class TValue>
class SkipListSuffix {
public:
class Iterator {
public:
Iterator(TIterator current) : current_(current) {}
TValue &operator*() { return *current_; }
bool operator!=(Iterator other) const {
return this->current_ != other.current_;
}
Iterator &operator++() {
++current_;
return *this;
}
private:
TIterator current_;
};
SkipListSuffix(const TIterator begin,
typename SkipList<TValue>::Accessor &&accessor)
: begin_(begin), accessor_(std::move(accessor)) {}
Iterator begin() const { return Iterator(begin_); }
Iterator end() { return Iterator(accessor_.end()); }
TIterator begin_;
typename SkipList<TValue>::Accessor accessor_;
};
/**
* @brief - Get all inserted vlists in TKey specific storage which
* still return true for the 'exists' function.
* @param index - index from which to get vlists
* @param skiplist_accessor - accessor used to get begin iterator, and that
* should be used to get end iterator as well.
* @param begin - starting iterator for vlist iteration.
* @param predicate - function which checks if TIndexEntry has a value that we
* are looking for
* @param t - current transaction, which determines visibility.
* @param exists - method which determines visibility of entry and version
* (record) of the underlying objects (vertex/edge)
@ -24,12 +69,18 @@ namespace IndexUtils {
* @return iterable collection of distinct vlist records<TRecord> for which
* exists function evaluates as true
*/
template <class TIndexEntry, class TRecord>
template <class TIterator, class TIndexEntry, class TRecord>
static auto GetVlists(
SkipList<TIndexEntry> &index, const tx::Transaction &t,
typename SkipList<TIndexEntry>::Accessor &&skiplist_accessor,
TIterator begin,
const std::function<bool(const TIndexEntry &entry)> predicate,
const tx::Transaction &t,
const std::function<bool(const TIndexEntry &, const TRecord *)> exists,
bool current_state = false) {
TIndexEntry *prev = nullptr;
auto range =
iter::takewhile(predicate, SkipListSuffix<TIterator, TIndexEntry>(
begin, std::move(skiplist_accessor)));
auto filtered = iter::filter(
[&t, exists, prev, current_state](TIndexEntry &entry) mutable {
// Check if the current entry could offer new possible return value
@ -57,7 +108,7 @@ static auto GetVlists(
return (current_state && new_record) ? exists(entry, new_record)
: exists(entry, old_record);
},
index.access());
std::move(range));
return iter::imap([](auto entry) { return entry.vlist_; },
std::move(filtered));
}

View File

@ -3,7 +3,7 @@
#include "data_structures/concurrent/concurrent_map.hpp"
#include "database/graph_db.hpp"
#include "database/graph_db_datatypes.hpp"
#include "database/indexes/index_utils.hpp"
#include "database/indexes/index_common.hpp"
#include "mvcc/version_list.hpp"
#include "storage/edge.hpp"
#include "storage/vertex.hpp"
@ -55,12 +55,14 @@ class KeyIndex {
* @return iterable collection of vlists records<TRecord> with the requested
* TKey.
*/
auto GetVlists(const TKey &key, tx::Transaction &t,
bool current_state = false) {
return IndexUtils::GetVlists<IndexEntry, TRecord>(
*GetKeyStorage(key), t,
[this, key](const IndexEntry &, const TRecord *record) {
return Exists(key, record);
auto GetVlists(const TKey &key, tx::Transaction &t, bool current_state) {
auto access = GetKeyStorage(key)->access();
auto begin = access.begin();
return IndexUtils::GetVlists<typename SkipList<IndexEntry>::Iterator,
IndexEntry, TRecord>(
std::move(access), begin, [](const IndexEntry &) { return true; }, t,
[key](const IndexEntry &, const TRecord *record) {
return KeyIndex::Exists(key, record);
},
current_state);
}
@ -87,8 +89,8 @@ class KeyIndex {
*/
void Refresh(const Id &id, tx::Engine &engine) {
return IndexUtils::Refresh<TKey, IndexEntry, TRecord>(
indices_, id, engine, [this](const TKey &key, const IndexEntry &entry) {
return Exists(key, entry.record_);
indices_, id, engine, [](const TKey &key, const IndexEntry &entry) {
return KeyIndex::Exists(key, entry.record_);
});
}
@ -157,7 +159,7 @@ class KeyIndex {
* @param label - label to check for.
* @return true if it contains, false otherwise.
*/
bool Exists(const GraphDbTypes::Label &label, const Vertex *const v) const {
static bool Exists(const GraphDbTypes::Label &label, const Vertex *const v) {
debug_assert(v != nullptr, "Vertex is nullptr.");
// We have to check for existance of label because the transaction
// might not see the label, or the label was deleted and not yet
@ -171,8 +173,8 @@ class KeyIndex {
* @param edge_type - edge_type to check for.
* @return true if it has that edge_type, false otherwise.
*/
bool Exists(const GraphDbTypes::EdgeType &edge_type,
const Edge *const e) const {
static bool Exists(const GraphDbTypes::EdgeType &edge_type,
const Edge *const e) {
debug_assert(e != nullptr, "Edge is nullptr.");
// We have to check for equality of edge types because the transaction
// might not see the edge type, or the edge type was deleted and not yet

View File

@ -3,7 +3,7 @@
#include "data_structures/concurrent/concurrent_map.hpp"
#include "database/graph_db.hpp"
#include "database/graph_db_datatypes.hpp"
#include "database/indexes/index_utils.hpp"
#include "database/indexes/index_common.hpp"
#include "mvcc/version_list.hpp"
#include "storage/edge.hpp"
#include "storage/vertex.hpp"
@ -12,6 +12,11 @@
/**
* @brief Implements LabelPropertyIndex.
* Currently this provides implementation for:
* acquiring all entries which contain the given label, and a given property
* sorted by the property value
* acquiring all non-unique entries with the given label, and property, with
* exactly one property value
*/
class LabelPropertyIndex {
public:
@ -159,13 +164,50 @@ class LabelPropertyIndex {
* @return iterable collection of vlists of vertex records with the requested
* key sorted ascendingly by the property value.
*/
auto GetVlists(const Key &key, const tx::Transaction &t,
bool current_state = false) {
auto GetVlists(const Key &key, const tx::Transaction &t, bool current_state) {
debug_assert(ready_for_use_.access().contains(key), "Index not yet ready.");
return IndexUtils::GetVlists<IndexEntry, Vertex>(
*GetKeyStorage(key), t,
[this, key](const IndexEntry &entry, const Vertex *const vertex) {
return Exists(key, entry.value_, vertex);
auto access = GetKeyStorage(key)->access();
auto begin = access.begin();
return IndexUtils::GetVlists<typename SkipList<IndexEntry>::Iterator,
IndexEntry, Vertex>(
std::move(access), begin, [](const IndexEntry &) { return true; }, t,
[key](const IndexEntry &entry, const Vertex *const vertex) {
return LabelPropertyIndex::Exists(key, entry.value_, vertex);
},
current_state);
}
/**
* @brief - Get all the inserted vlists in key specific storage which still
* have that label and property visible in this transaction with property
* value equal to 'value'.
* @param key - Label+Property to query.
* @param value - vlists with this value will be returned
* @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 of vertex records with the requested
* key and value
*/
auto GetVlists(const Key &key, const PropertyValue &value,
const tx::Transaction &t, bool current_state) {
debug_assert(ready_for_use_.access().contains(key), "Index not yet ready.");
auto access = GetKeyStorage(key)->access();
auto start_iter =
access.find_or_larger<typename SkipList<IndexEntry>::Iterator,
IndexEntry>(IndexEntry(value, nullptr, nullptr));
return IndexUtils::GetVlists<typename SkipList<IndexEntry>::Iterator,
IndexEntry, Vertex>(
std::move(access), start_iter,
[value](const IndexEntry &entry) {
return !IndexEntry::Cmp(value, entry.value_) &&
!IndexEntry::Cmp(entry.value_, value);
},
t,
[key](const IndexEntry &entry, const Vertex *const vertex) {
return LabelPropertyIndex::Exists(key, entry.value_, vertex);
},
current_state);
}
@ -206,8 +248,8 @@ class LabelPropertyIndex {
*/
void Refresh(const Id &id, tx::Engine &engine) {
return IndexUtils::Refresh<Key, IndexEntry, Vertex>(
indices_, id, engine, [this](const Key &key, const IndexEntry &entry) {
return Exists(key, entry.value_, entry.record_);
indices_, id, engine, [](const Key &key, const IndexEntry &entry) {
return LabelPropertyIndex::Exists(key, entry.value_, entry.record_);
});
}
@ -346,12 +388,12 @@ class LabelPropertyIndex {
/**
* @brief - Check if Vertex contains label and property with the given
* value.
* @param key - label and parameter to check for.
* @param value - value of parameter to compare
* @param key - label and property to check for.
* @param value - value of property to compare
* @return true if it contains, false otherwise.
*/
bool Exists(const Key &key, const PropertyValue &value,
const Vertex *const v) const {
static bool Exists(const Key &key, const PropertyValue &value,
const Vertex *const v) {
debug_assert(v != nullptr, "Vertex is nullptr.");
// We have to check for existance of label because the transaction
// might not see the label, or the label was deleted and not yet

View File

@ -32,11 +32,11 @@ bool Snapshooter::Encode(const fs::path &snapshot_file,
int64_t vertex_num = 0, edge_num = 0;
buffer.Open(snapshot_file);
for (const auto &vertex : db_accessor_.vertices()) {
for (const auto &vertex : db_accessor_.vertices(false)) {
encoder.WriteVertex(vertex);
vertex_num++;
}
for (const auto &edge : db_accessor_.edges()) {
for (const auto &edge : db_accessor_.edges(false)) {
encoder.WriteEdge(edge);
edge_num++;
}

View File

@ -39,8 +39,8 @@ bool run_general_query(GraphDbAccessor &db_accessor, const Parameters &args,
// TODO dgleich: this code is very inefficient as it first makes a copy
// of all the vertices/edges, and filters aftwarwards. I warned about this
// happening in code review!!!
auto vertices_iterator = db_accessor.vertices();
auto edge_iterator = db_accessor.edges();
auto vertices_iterator = db_accessor.vertices(false);
auto edge_iterator = db_accessor.edges(false);
std::vector<VertexAccessor> vertices(vertices_iterator.begin(),
vertices_iterator.end());
std::vector<EdgeAccessor> edges(edge_iterator.begin(), edge_iterator.end());

View File

@ -17,7 +17,7 @@ class CPUPlan : public PlanInterface<Stream> {
public:
bool run(GraphDbAccessor &db_accessor, const Parameters &args,
Stream &stream) {
for (auto v : db_accessor.vertices()) db_accessor.detach_remove_vertex(v);
for (auto v : db_accessor.vertices(false)) db_accessor.detach_remove_vertex(v);
std::vector<std::string> headers;
stream.Header(headers);
return true;

View File

@ -20,7 +20,7 @@ class CPUPlan : public PlanInterface<Stream> {
Stream &stream) {
std::vector<std::string> headers{std::string("g")};
stream.Header(headers);
for (auto vertex : db_accessor.vertices()) {
for (auto vertex : db_accessor.vertices(false)) {
if (vertex.has_label(db_accessor.label("garment"))) {
TypedValue prop = vertex.PropsAt(db_accessor.property("garment_id"));
if (prop.type() == TypedValue::Type::Null) continue;

View File

@ -22,7 +22,7 @@ class CPUPlan : public PlanInterface<Stream> {
std::vector<std::string> headers{std::string("r")};
stream.Header(headers);
std::vector<VertexAccessor> g1_set, g2_set;
for (auto g1 : db_accessor.vertices()) {
for (auto g1 : db_accessor.vertices(false)) {
if (g1.has_label(db_accessor.label("garment"))) {
TypedValue prop = g1.PropsAt(db_accessor.property("garment_id"));
if (prop.type() == TypedValue::Type::Null) continue;
@ -32,7 +32,7 @@ class CPUPlan : public PlanInterface<Stream> {
g1_set.push_back(g1);
}
}
for (auto g2 : db_accessor.vertices()) {
for (auto g2 : db_accessor.vertices(false)) {
if (g2.has_label(db_accessor.label("garment"))) {
auto prop = g2.PropsAt(db_accessor.property("garment_id"));
if (prop.type() == PropertyValue::Type::Null) continue;

View File

@ -18,7 +18,7 @@ bool run_general_query(GraphDbAccessor &db_accessor, const Parameters &args,
Stream &stream, const std::string &general_label) {
std::vector<std::string> headers{std::string("g")};
stream.Header(headers);
for (auto vertex : db_accessor.vertices()) {
for (auto vertex : db_accessor.vertices(false)) {
if (vertex.has_label(db_accessor.label("garment"))) {
query::TypedValue prop =
vertex.PropsAt(db_accessor.property("garment_id"));

View File

@ -20,7 +20,7 @@ class CPUPlan : public PlanInterface<Stream> {
Stream &stream) {
std::vector<std::string> headers{std::string("p")};
stream.Header(headers);
for (auto vertex : db_accessor.vertices()) {
for (auto vertex : db_accessor.vertices(false)) {
if (vertex.has_label(db_accessor.label("profile"))) {
TypedValue prop = vertex.PropsAt(db_accessor.property("profile_id"));
if (prop.type() == TypedValue::Type::Null) continue;

View File

@ -43,7 +43,7 @@ class CPUPlan : public PlanInterface<Stream> {
if (cmp.type() != TypedValue::Type::Bool) return false;
return cmp.Value<bool>();
};
for (auto edge : db_accessor.edges()) {
for (auto edge : db_accessor.edges(false)) {
auto from = edge.from();
auto to = edge.to();
if (edge.edge_type() != db_accessor.edge_type("score")) continue;

View File

@ -22,7 +22,7 @@ class CPUPlan : public PlanInterface<Stream> {
std::vector<std::string> headers{std::string("r")};
stream.Header(headers);
std::vector<VertexAccessor> g1_set, g2_set;
for (auto g1 : db_accessor.vertices()) {
for (auto g1 : db_accessor.vertices(false)) {
if (g1.has_label(db_accessor.label("profile"))) {
auto prop = TypedValue(g1.PropsAt(db_accessor.property("profile_id")));
if (prop.type() == TypedValue::Type::Null) continue;
@ -38,7 +38,7 @@ class CPUPlan : public PlanInterface<Stream> {
g1_set.push_back(g1);
}
}
for (auto g2 : db_accessor.vertices()) {
for (auto g2 : db_accessor.vertices(false)) {
if (g2.has_label(db_accessor.label("garment"))) {
auto prop = TypedValue(g2.PropsAt(db_accessor.property("garment_id")));
if (prop.type() == TypedValue::Type::Null) continue;

View File

@ -42,7 +42,7 @@ class CPUPlan : public PlanInterface<Stream> {
if (cmp.type() != TypedValue::Type::Bool) return false;
return cmp.Value<bool>();
};
for (auto edge : db_accessor.edges()) {
for (auto edge : db_accessor.edges(false)) {
auto from = edge.from();
auto to = edge.to();
if (edge.edge_type() != db_accessor.edge_type("score")) continue;

View File

@ -39,8 +39,8 @@ TEST(LabelsIndex, UniqueInsert) {
// Check if index filters duplicates.
TEST(LabelsIndex, UniqueFilter) {
KeyIndex<GraphDbTypes::Label, Vertex> index;
Dbms dbms;
KeyIndex<GraphDbTypes::Label, Vertex> index;
auto dba = dbms.active();
tx::Engine engine;
@ -72,7 +72,7 @@ TEST(LabelsIndex, UniqueFilter) {
sort(expected.begin(),
expected.end()); // Entries will be sorted by vlist pointers.
int cnt = 0;
for (auto vlist : index.GetVlists(label1, *t3)) {
for (auto vlist : index.GetVlists(label1, *t3, false)) {
EXPECT_LT(cnt, expected.size());
EXPECT_EQ(vlist, expected[cnt++]);
}
@ -123,7 +123,7 @@ TEST(LabelsIndexDb, AddGetZeroLabels) {
auto dba = dbms.active();
auto vertex = dba->insert_vertex();
vertex.add_label(dba->label("test"));
auto collection = dba->vertices(dba->label("test"));
auto collection = dba->vertices(dba->label("test"), false);
std::vector<VertexAccessor> collection_vector(collection.begin(),
collection.end());
EXPECT_EQ(collection_vector.size(), (size_t)0);
@ -150,9 +150,9 @@ TEST(LabelsIndexDb, AddGetRemoveLabel) {
{
auto dba = dbms.active();
auto filtered = dba->vertices(dba->label("test"));
auto filtered = dba->vertices(dba->label("test"), false);
std::vector<VertexAccessor> collection(filtered.begin(), filtered.end());
auto vertices = dba->vertices();
auto vertices = dba->vertices(false);
std::vector<VertexAccessor> expected_collection;
for (auto vertex : vertices) {
@ -179,9 +179,9 @@ TEST(LabelsIndexDb, AddGetRemoveLabel) {
{
auto dba = dbms.active();
auto filtered = dba->vertices(dba->label("test"));
auto filtered = dba->vertices(dba->label("test"), false);
std::vector<VertexAccessor> collection(filtered.begin(), filtered.end());
auto vertices = dba->vertices();
auto vertices = dba->vertices(false);
std::vector<VertexAccessor> expected_collection;
for (auto vertex : vertices) {

View File

@ -150,7 +150,7 @@ TEST_F(LabelPropertyIndexComplexTest, UniqueFilter) {
EXPECT_EQ(index.Count(*key), 2);
auto t3 = engine.begin();
auto iter = index.GetVlists(*key, *t3);
auto iter = index.GetVlists(*key, *t3, false);
EXPECT_EQ(std::distance(iter.begin(), iter.end()), 1);
t3->commit();
}
@ -159,11 +159,11 @@ TEST_F(LabelPropertyIndexComplexTest, UniqueFilter) {
TEST_F(LabelPropertyIndexComplexTest, RemoveLabel) {
index.UpdateOnLabelProperty(vlist, vertex);
auto iter1 = index.GetVlists(*key, *t);
auto iter1 = index.GetVlists(*key, *t, false);
EXPECT_EQ(std::distance(iter1.begin(), iter1.end()), 1);
vertex->labels_.clear();
auto iter2 = index.GetVlists(*key, *t);
auto iter2 = index.GetVlists(*key, *t, false);
EXPECT_EQ(std::distance(iter2.begin(), iter2.end()), 0);
}
@ -171,11 +171,11 @@ TEST_F(LabelPropertyIndexComplexTest, RemoveLabel) {
TEST_F(LabelPropertyIndexComplexTest, RemoveProperty) {
index.UpdateOnLabelProperty(vlist, vertex);
auto iter1 = index.GetVlists(*key, *t);
auto iter1 = index.GetVlists(*key, *t, false);
EXPECT_EQ(std::distance(iter1.begin(), iter1.end()), 1);
vertex->properties_.clear();
auto iter2 = index.GetVlists(*key, *t);
auto iter2 = index.GetVlists(*key, *t, false);
EXPECT_EQ(std::distance(iter2.begin(), iter2.end()), 0);
}
@ -187,7 +187,7 @@ TEST_F(LabelPropertyIndexComplexTest, Refresh) {
vertex->labels_.clear();
vertex->properties_.clear();
index.Refresh(engine.count() + 1, engine);
auto iter = index.GetVlists(*key, *t);
auto iter = index.GetVlists(*key, *t, false);
EXPECT_EQ(std::distance(iter.begin(), iter.end()), 0);
}

View File

@ -7,7 +7,6 @@
#include "storage/edge_accessor.hpp"
#include "storage/vertex_accessor.hpp"
template <typename TIterable>
auto Count(TIterable iterable) {
return std::distance(iterable.begin(), iterable.end());
@ -23,36 +22,36 @@ TEST(GraphDbAccessorTest, InsertVertex) {
Dbms dbms;
auto accessor = dbms.active();
EXPECT_EQ(Count(accessor->vertices()), 0);
EXPECT_EQ(Count(accessor->vertices(false)), 0);
accessor->insert_vertex();
EXPECT_EQ(Count(accessor->vertices()), 0);
EXPECT_EQ(Count(accessor->vertices(false)), 0);
EXPECT_EQ(Count(accessor->vertices(true)), 1);
accessor->advance_command();
EXPECT_EQ(Count(accessor->vertices()), 1);
EXPECT_EQ(Count(accessor->vertices(false)), 1);
accessor->insert_vertex();
EXPECT_EQ(Count(accessor->vertices()), 1);
EXPECT_EQ(Count(accessor->vertices(false)), 1);
EXPECT_EQ(Count(accessor->vertices(true)), 2);
accessor->advance_command();
EXPECT_EQ(Count(accessor->vertices()), 2);
EXPECT_EQ(Count(accessor->vertices(false)), 2);
}
TEST(GraphDbAccessorTest, RemoveVertexSameTransaction) {
Dbms dbms;
auto accessor = dbms.active();
EXPECT_EQ(Count(accessor->vertices()), 0);
EXPECT_EQ(Count(accessor->vertices(false)), 0);
auto va1 = accessor->insert_vertex();
accessor->advance_command();
EXPECT_EQ(Count(accessor->vertices()), 1);
EXPECT_EQ(Count(accessor->vertices(false)), 1);
EXPECT_TRUE(accessor->remove_vertex(va1));
EXPECT_EQ(Count(accessor->vertices()), 1);
EXPECT_EQ(Count(accessor->vertices(false)), 1);
EXPECT_EQ(Count(accessor->vertices(true)), 0);
accessor->advance_command();
EXPECT_EQ(Count(accessor->vertices()), 0);
EXPECT_EQ(Count(accessor->vertices(false)), 0);
EXPECT_EQ(Count(accessor->vertices(true)), 0);
}
@ -66,15 +65,15 @@ TEST(GraphDbAccessorTest, RemoveVertexDifferentTransaction) {
// second transaction checks that it sees it, and deletes it
auto accessor2 = dbms.active();
EXPECT_EQ(Count(accessor2->vertices()), 1);
EXPECT_EQ(Count(accessor2->vertices(false)), 1);
EXPECT_EQ(Count(accessor2->vertices(true)), 1);
for (auto vertex_accessor : accessor2->vertices())
for (auto vertex_accessor : accessor2->vertices(false))
accessor2->remove_vertex(vertex_accessor);
accessor2->commit();
// third transaction checks that it does not see the vertex
auto accessor3 = dbms.active();
EXPECT_EQ(Count(accessor3->vertices()), 0);
EXPECT_EQ(Count(accessor3->vertices(false)), 0);
EXPECT_EQ(Count(accessor3->vertices(true)), 0);
}
@ -92,10 +91,10 @@ 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(false)), 0);
EXPECT_EQ(Count(dba->edges(true)), 1);
dba->advance_command();
EXPECT_EQ(Count(dba->edges()), 1);
EXPECT_EQ(Count(dba->edges(false)), 1);
EXPECT_EQ(Count(dba->edges(true)), 1);
EXPECT_EQ(va1.out().begin()->to(), va2);
EXPECT_EQ(va2.in().begin()->from(), va1);
@ -110,7 +109,7 @@ TEST(GraphDbAccessorTest, InsertEdge) {
EXPECT_EQ(Count(dba->edges(false)), 1);
EXPECT_EQ(Count(dba->edges(true)), 2);
dba->advance_command();
EXPECT_EQ(Count(dba->edges()), 2);
EXPECT_EQ(Count(dba->edges(false)), 2);
EXPECT_EQ(va3.out().begin()->to(), va2);
EXPECT_EQ(va1.in_degree(), 0);
EXPECT_EQ(va1.out_degree(), 1);
@ -131,28 +130,28 @@ 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(Count(dba->edges()), 2);
EXPECT_EQ(Count(dba->edges(false)), 2);
EXPECT_EQ(Count(dba->edges(true)), 2);
// remove all [:hates] edges
for (auto edge : dba->edges())
for (auto edge : dba->edges(false))
if (edge.edge_type() == dba->edge_type("hates")) dba->remove_edge(edge);
EXPECT_EQ(Count(dba->edges()), 2);
EXPECT_EQ(Count(dba->edges(false)), 2);
EXPECT_EQ(Count(dba->edges(true)), 1);
// current state: (v1) - [:likes] -> (v2), (v3)
dba->advance_command();
EXPECT_EQ(Count(dba->edges()), 1);
EXPECT_EQ(Count(dba->edges(false)), 1);
EXPECT_EQ(Count(dba->edges(true)), 1);
EXPECT_EQ(Count(dba->vertices()), 3);
EXPECT_EQ(Count(dba->vertices(false)), 3);
EXPECT_EQ(Count(dba->vertices(true)), 3);
for (auto edge : dba->edges()) {
for (auto edge : dba->edges(false)) {
EXPECT_EQ(edge.edge_type(), dba->edge_type("likes"));
auto v1 = edge.from();
auto v2 = edge.to();
// ensure correct connectivity for all the vertices
for (auto vertex : dba->vertices()) {
for (auto vertex : dba->vertices(false)) {
if (vertex == v1) {
EXPECT_EQ(vertex.in_degree(), 0);
EXPECT_EQ(vertex.out_degree(), 1);
@ -184,58 +183,58 @@ TEST(GraphDbAccessorTest, DetachRemoveVertex) {
for (auto &vertex : vertices) vertex.Reconstruct();
// ensure that plain remove does NOT work
EXPECT_EQ(Count(dba->vertices()), 4);
EXPECT_EQ(Count(dba->edges()), 3);
EXPECT_EQ(Count(dba->vertices(false)), 4);
EXPECT_EQ(Count(dba->edges(false)), 3);
EXPECT_FALSE(dba->remove_vertex(vertices[0]));
EXPECT_FALSE(dba->remove_vertex(vertices[1]));
EXPECT_FALSE(dba->remove_vertex(vertices[2]));
EXPECT_EQ(Count(dba->vertices()), 4);
EXPECT_EQ(Count(dba->edges()), 3);
EXPECT_EQ(Count(dba->vertices(false)), 4);
EXPECT_EQ(Count(dba->edges(false)), 3);
dba->detach_remove_vertex(vertices[2]);
EXPECT_EQ(Count(dba->vertices()), 4);
EXPECT_EQ(Count(dba->vertices(false)), 4);
EXPECT_EQ(Count(dba->vertices(true)), 3);
EXPECT_EQ(Count(dba->edges()), 3);
EXPECT_EQ(Count(dba->edges(false)), 3);
EXPECT_EQ(Count(dba->edges(true)), 1);
dba->advance_command();
for (auto &vertex : vertices) vertex.Reconstruct();
EXPECT_EQ(Count(dba->vertices()), 3);
EXPECT_EQ(Count(dba->edges()), 1);
EXPECT_EQ(Count(dba->vertices(false)), 3);
EXPECT_EQ(Count(dba->edges(false)), 1);
EXPECT_TRUE(dba->remove_vertex(vertices[3]));
EXPECT_EQ(Count(dba->vertices(true)), 2);
EXPECT_EQ(Count(dba->vertices()), 3);
EXPECT_EQ(Count(dba->vertices(false)), 3);
dba->advance_command();
for (auto &vertex : vertices) vertex.Reconstruct();
EXPECT_EQ(Count(dba->vertices()), 2);
EXPECT_EQ(Count(dba->edges()), 1);
for (auto va : dba->vertices()) EXPECT_FALSE(dba->remove_vertex(va));
EXPECT_EQ(Count(dba->vertices(false)), 2);
EXPECT_EQ(Count(dba->edges(false)), 1);
for (auto va : dba->vertices(false)) EXPECT_FALSE(dba->remove_vertex(va));
dba->advance_command();
for (auto &vertex : vertices) vertex.Reconstruct();
EXPECT_EQ(Count(dba->vertices()), 2);
EXPECT_EQ(Count(dba->edges()), 1);
for (auto va : dba->vertices()) {
EXPECT_EQ(Count(dba->vertices(false)), 2);
EXPECT_EQ(Count(dba->edges(false)), 1);
for (auto va : dba->vertices(false)) {
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);
EXPECT_EQ(Count(dba->vertices(false)), 2);
dba->advance_command();
for (auto &vertex : vertices) vertex.Reconstruct();
EXPECT_EQ(Count(dba->vertices()), 1);
EXPECT_EQ(Count(dba->edges()), 0);
EXPECT_EQ(Count(dba->vertices(false)), 1);
EXPECT_EQ(Count(dba->edges(false)), 0);
// remove the last vertex, it has no connections
// so that should work
for (auto va : dba->vertices()) EXPECT_TRUE(dba->remove_vertex(va));
for (auto va : dba->vertices(false)) EXPECT_TRUE(dba->remove_vertex(va));
dba->advance_command();
EXPECT_EQ(Count(dba->vertices()), 0);
EXPECT_EQ(Count(dba->edges()), 0);
EXPECT_EQ(Count(dba->vertices(false)), 0);
EXPECT_EQ(Count(dba->edges(false)), 0);
}
TEST(GraphDbAccessorTest, DetachRemoveVertexMultiple) {
@ -258,30 +257,30 @@ TEST(GraphDbAccessorTest, DetachRemoveVertexMultiple) {
dba->advance_command();
for (auto &vertex : vertices) vertex.Reconstruct();
EXPECT_EQ(Count(dba->vertices()), N);
EXPECT_EQ(Count(dba->edges()), N * N);
EXPECT_EQ(Count(dba->vertices(false)), N);
EXPECT_EQ(Count(dba->edges(false)), N * N);
// detach delete one edge
dba->detach_remove_vertex(vertices[0]);
dba->advance_command();
for (auto &vertex : vertices) vertex.Reconstruct();
EXPECT_EQ(Count(dba->vertices()), N - 1);
EXPECT_EQ(Count(dba->edges()), (N - 1) * (N - 1));
EXPECT_EQ(Count(dba->vertices(false)), N - 1);
EXPECT_EQ(Count(dba->edges(false)), (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(Count(dba->vertices()), N - 3);
EXPECT_EQ(Count(dba->edges()), (N - 3) * (N - 3));
EXPECT_EQ(Count(dba->vertices(false)), N - 3);
EXPECT_EQ(Count(dba->edges(false)), (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(Count(dba->vertices()), 0);
EXPECT_EQ(Count(dba->edges()), 0);
EXPECT_EQ(Count(dba->vertices(false)), 0);
EXPECT_EQ(Count(dba->edges(false)), 0);
}
TEST(GraphDbAccessorTest, Labels) {

View File

@ -142,6 +142,31 @@ TEST(GraphDbAccessor, BuildIndexDouble) {
EXPECT_THROW(dba->BuildIndex(label, property), utils::BasicException);
}
// Inserts vertices with properties with integers and filters to get exact
// vertices with an exact integer.
TEST(GraphDbAccessor, FilterLabelPropertySpecificValue) {
Dbms dbms;
auto dba = dbms.active();
auto label = dba->label("lab1");
auto property = dba->property("prop1");
dba->BuildIndex(label, property);
dba->commit();
auto dba2 = dbms.active();
for (int i = 1; i <= 5; ++i) {
for (int j = 1; j <= i; ++j) {
auto vertex = dba2->insert_vertex();
vertex.add_label(label);
vertex.PropsSet(property, i);
}
}
dba2->commit();
auto dba3 = dbms.active();
for (int i = 1; i <= 5; ++i)
EXPECT_EQ(Count(dba3->vertices(label, property, PropertyValue(i), false)),
i);
}
// Inserts integers, double, lists, booleans into index and check if they are
// sorted as they should be sorted.
TEST(GraphDbAccessor, SortedLabelPropertyEntries) {
@ -252,24 +277,24 @@ TEST(GraphDbAccessor, VisibilityAfterInsertion) {
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, false)), 0);
EXPECT_EQ(Count(dba->vertices(lab1, true)), 1);
EXPECT_EQ(Count(dba->vertices(lab2)), 0);
EXPECT_EQ(Count(dba->vertices(lab2, false)), 0);
EXPECT_EQ(Count(dba->vertices(lab2, true)), 0);
EXPECT_EQ(Count(dba->edges(type1)), 0);
EXPECT_EQ(Count(dba->edges(type1, false)), 0);
EXPECT_EQ(Count(dba->edges(type1, true)), 1);
EXPECT_EQ(Count(dba->edges(type2)), 0);
EXPECT_EQ(Count(dba->edges(type2, false)), 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, false)), 1);
EXPECT_EQ(Count(dba->vertices(lab1, true)), 1);
EXPECT_EQ(Count(dba->vertices(lab2)), 0);
EXPECT_EQ(Count(dba->vertices(lab2, false)), 0);
EXPECT_EQ(Count(dba->vertices(lab2, true)), 0);
EXPECT_EQ(Count(dba->edges(type1)), 1);
EXPECT_EQ(Count(dba->edges(type1, false)), 1);
EXPECT_EQ(Count(dba->edges(type1, true)), 1);
EXPECT_EQ(Count(dba->edges(type2)), 0);
EXPECT_EQ(Count(dba->edges(type2, false)), 0);
EXPECT_EQ(Count(dba->edges(type2, true)), 0);
}
@ -281,32 +306,32 @@ TEST(GraphDbAccessor, VisibilityAfterDeletion) {
dba->advance_command();
auto type = dba->edge_type("type");
for (int j = 0; j < 3; ++j) {
auto vertices_it = dba->vertices().begin();
auto vertices_it = dba->vertices(false).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, false)), 5);
EXPECT_EQ(Count(dba->vertices(lab, true)), 5);
EXPECT_EQ(Count(dba->edges(type)), 3);
EXPECT_EQ(Count(dba->edges(type, false)), 3);
EXPECT_EQ(Count(dba->edges(type, true)), 3);
// delete two edges
auto edges_it = dba->edges().begin();
auto edges_it = dba->edges(false).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, false)), 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, false)), 1);
EXPECT_EQ(Count(dba->edges(type, true)), 1);
// detach-delete 2 vertices
auto vertices_it = dba->vertices().begin();
auto vertices_it = dba->vertices(false).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, false)), 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, false)), 3);
EXPECT_EQ(Count(dba->vertices(lab, true)), 3);
}

View File

@ -431,7 +431,7 @@ TEST(QueryPlan, AggregateCountEdgeCases) {
EXPECT_EQ(0, count());
// one vertex, property set
for (VertexAccessor va : dba->vertices()) va.PropsSet(prop, 42);
for (VertexAccessor va : dba->vertices(false)) va.PropsSet(prop, 42);
dba->advance_command();
EXPECT_EQ(1, count());
@ -441,7 +441,7 @@ TEST(QueryPlan, AggregateCountEdgeCases) {
EXPECT_EQ(1, count());
// two vertices, both with property set
for (VertexAccessor va : dba->vertices()) va.PropsSet(prop, 42);
for (VertexAccessor va : dba->vertices(false)) va.PropsSet(prop, 42);
dba->advance_command();
EXPECT_EQ(2, count());
}

View File

@ -101,7 +101,7 @@ TEST(QueryPlan, CreateLimit) {
EXPECT_EQ(1, PullAll(skip, *dba, symbol_table));
dba->advance_command();
EXPECT_EQ(3, CountIterable(dba->vertices()));
EXPECT_EQ(3, CountIterable(dba->vertices(false)));
}
TEST(QueryPlan, OrderBy) {
@ -125,9 +125,9 @@ TEST(QueryPlan, OrderBy) {
for (const auto &order_value_pair : orderable) {
const auto &values = order_value_pair.second;
// empty database
for (auto &vertex : dba->vertices()) dba->detach_remove_vertex(vertex);
for (auto &vertex : dba->vertices(false)) dba->detach_remove_vertex(vertex);
dba->advance_command();
ASSERT_EQ(0, CountIterable(dba->vertices()));
ASSERT_EQ(0, CountIterable(dba->vertices(false)));
// take some effort to shuffle the values
// because we are testing that something not ordered gets ordered
@ -243,16 +243,16 @@ TEST(QueryPlan, OrderByExceptions) {
for (const auto &pair : exception_pairs) {
// empty database
for (auto &vertex : dba->vertices()) dba->detach_remove_vertex(vertex);
for (auto &vertex : dba->vertices(false)) dba->detach_remove_vertex(vertex);
dba->advance_command();
ASSERT_EQ(0, CountIterable(dba->vertices()));
ASSERT_EQ(0, CountIterable(dba->vertices(false)));
// make two vertices, and set values
dba->insert_vertex().PropsSet(prop, pair.first);
dba->insert_vertex().PropsSet(prop, pair.second);
dba->advance_command();
ASSERT_EQ(2, CountIterable(dba->vertices()));
for (const auto &va : dba->vertices())
ASSERT_EQ(2, CountIterable(dba->vertices(false)));
for (const auto &va : dba->vertices(false))
ASSERT_NE(va.PropsAt(prop).type(), PropertyValue::Type::Null);
// order by and expect an exception

View File

@ -43,7 +43,7 @@ TEST(QueryPlan, CreateNodeWithAttributes) {
// count the number of vertices
int vertex_count = 0;
for (VertexAccessor vertex : dba->vertices()) {
for (VertexAccessor vertex : dba->vertices(false)) {
vertex_count++;
EXPECT_EQ(vertex.labels().size(), 1);
EXPECT_EQ(*vertex.labels().begin(), label);
@ -94,7 +94,7 @@ TEST(QueryPlan, CreateReturn) {
EXPECT_EQ(42, results[0][1].Value<int64_t>());
dba->advance_command();
EXPECT_EQ(1, CountIterable(dba->vertices()));
EXPECT_EQ(1, CountIterable(dba->vertices(false)));
}
TEST(QueryPlan, CreateExpand) {
@ -111,8 +111,8 @@ TEST(QueryPlan, CreateExpand) {
auto test_create_path = [&](bool cycle, int expected_nodes_created,
int expected_edges_created) {
int before_v = CountIterable(dba->vertices());
int before_e = CountIterable(dba->edges());
int before_v = CountIterable(dba->vertices(false));
int before_e = CountIterable(dba->edges(false));
// data for the first node
auto n = NODE("n");
@ -141,15 +141,15 @@ TEST(QueryPlan, CreateExpand) {
PullAll(create_expand, *dba, symbol_table);
dba->advance_command();
EXPECT_EQ(CountIterable(dba->vertices()) - before_v,
EXPECT_EQ(CountIterable(dba->vertices(false)) - before_v,
expected_nodes_created);
EXPECT_EQ(CountIterable(dba->edges()) - before_e, expected_edges_created);
EXPECT_EQ(CountIterable(dba->edges(false)) - before_e, expected_edges_created);
};
test_create_path(false, 2, 1);
test_create_path(true, 1, 1);
for (VertexAccessor vertex : dba->vertices()) {
for (VertexAccessor vertex : dba->vertices(false)) {
EXPECT_EQ(vertex.labels().size(), 1);
GraphDbTypes::Label label = vertex.labels()[0];
if (label == label_node_1) {
@ -163,7 +163,7 @@ TEST(QueryPlan, CreateExpand) {
FAIL();
}
for (EdgeAccessor edge : dba->edges()) {
for (EdgeAccessor edge : dba->edges(false)) {
EXPECT_EQ(edge.edge_type(), edge_type);
EXPECT_EQ(edge.PropsAt(property).Value<int64_t>(), 3);
}
@ -191,10 +191,10 @@ TEST(QueryPlan, MatchCreateNode) {
// creation op
auto create_node = std::make_shared<CreateNode>(m, n_scan_all.op_);
EXPECT_EQ(CountIterable(dba->vertices()), 3);
EXPECT_EQ(CountIterable(dba->vertices(false)), 3);
PullAll(create_node, *dba, symbol_table);
dba->advance_command();
EXPECT_EQ(CountIterable(dba->vertices()), 6);
EXPECT_EQ(CountIterable(dba->vertices(false)), 6);
}
TEST(QueryPlan, MatchCreateExpand) {
@ -217,8 +217,8 @@ TEST(QueryPlan, MatchCreateExpand) {
auto test_create_path = [&](bool cycle, int expected_nodes_created,
int expected_edges_created) {
int before_v = CountIterable(dba->vertices());
int before_e = CountIterable(dba->edges());
int before_v = CountIterable(dba->vertices(false));
int before_e = CountIterable(dba->edges(false));
// data for the first node
auto n_scan_all = MakeScanAll(storage, symbol_table, "n");
@ -239,9 +239,9 @@ TEST(QueryPlan, MatchCreateExpand) {
PullAll(create_expand, *dba, symbol_table);
dba->advance_command();
EXPECT_EQ(CountIterable(dba->vertices()) - before_v,
EXPECT_EQ(CountIterable(dba->vertices(false)) - before_v,
expected_nodes_created);
EXPECT_EQ(CountIterable(dba->edges()) - before_e, expected_edges_created);
EXPECT_EQ(CountIterable(dba->edges(false)) - before_e, expected_edges_created);
};
test_create_path(false, 3, 3);
@ -261,8 +261,8 @@ TEST(QueryPlan, Delete) {
dba->insert_edge(vertices[j], vertices[k], type);
dba->advance_command();
EXPECT_EQ(4, CountIterable(dba->vertices()));
EXPECT_EQ(6, CountIterable(dba->edges()));
EXPECT_EQ(4, CountIterable(dba->vertices(false)));
EXPECT_EQ(6, CountIterable(dba->edges(false)));
AstTreeStorage storage;
SymbolTable symbol_table;
@ -276,8 +276,8 @@ TEST(QueryPlan, Delete) {
n.op_, std::vector<Expression *>{n_get}, false);
EXPECT_THROW(PullAll(delete_op, *dba, symbol_table), QueryRuntimeException);
dba->advance_command();
EXPECT_EQ(4, CountIterable(dba->vertices()));
EXPECT_EQ(6, CountIterable(dba->edges()));
EXPECT_EQ(4, CountIterable(dba->vertices(false)));
EXPECT_EQ(6, CountIterable(dba->edges(false)));
}
// detach delete a single vertex
@ -290,8 +290,8 @@ TEST(QueryPlan, Delete) {
Frame frame(symbol_table.max_position());
delete_op->MakeCursor(*dba)->Pull(frame, symbol_table);
dba->advance_command();
EXPECT_EQ(3, CountIterable(dba->vertices()));
EXPECT_EQ(3, CountIterable(dba->edges()));
EXPECT_EQ(3, CountIterable(dba->vertices(false)));
EXPECT_EQ(3, CountIterable(dba->edges(false)));
}
// delete all remaining edges
@ -305,8 +305,8 @@ TEST(QueryPlan, Delete) {
r_m.op_, std::vector<Expression *>{r_get}, false);
PullAll(delete_op, *dba, symbol_table);
dba->advance_command();
EXPECT_EQ(3, CountIterable(dba->vertices()));
EXPECT_EQ(0, CountIterable(dba->edges()));
EXPECT_EQ(3, CountIterable(dba->vertices(false)));
EXPECT_EQ(0, CountIterable(dba->edges(false)));
}
// delete all remaining vertices
@ -318,8 +318,8 @@ TEST(QueryPlan, Delete) {
n.op_, std::vector<Expression *>{n_get}, false);
PullAll(delete_op, *dba, symbol_table);
dba->advance_command();
EXPECT_EQ(0, CountIterable(dba->vertices()));
EXPECT_EQ(0, CountIterable(dba->edges()));
EXPECT_EQ(0, CountIterable(dba->vertices(false)));
EXPECT_EQ(0, CountIterable(dba->edges(false)));
}
}
@ -343,8 +343,8 @@ TEST(QueryPlan, DeleteTwiceDeleteBlockingEdge) {
auto v2 = dba->insert_vertex();
dba->insert_edge(v1, v2, dba->edge_type("T"));
dba->advance_command();
EXPECT_EQ(2, CountIterable(dba->vertices()));
EXPECT_EQ(1, CountIterable(dba->edges()));
EXPECT_EQ(2, CountIterable(dba->vertices(false)));
EXPECT_EQ(1, CountIterable(dba->edges(false)));
AstTreeStorage storage;
SymbolTable symbol_table;
@ -365,8 +365,8 @@ TEST(QueryPlan, DeleteTwiceDeleteBlockingEdge) {
r_m.op_, std::vector<Expression *>{n_get, r_get, m_get}, detach);
EXPECT_EQ(2, PullAll(delete_op, *dba, symbol_table));
dba->advance_command();
EXPECT_EQ(0, CountIterable(dba->vertices()));
EXPECT_EQ(0, CountIterable(dba->edges()));
EXPECT_EQ(0, CountIterable(dba->vertices(false)));
EXPECT_EQ(0, CountIterable(dba->edges(false)));
};
test_delete(true);
@ -385,8 +385,8 @@ TEST(QueryPlan, DeleteReturn) {
}
dba->advance_command();
EXPECT_EQ(4, CountIterable(dba->vertices()));
EXPECT_EQ(0, CountIterable(dba->edges()));
EXPECT_EQ(4, CountIterable(dba->vertices(false)));
EXPECT_EQ(0, CountIterable(dba->edges(false)));
AstTreeStorage storage;
SymbolTable symbol_table;
@ -408,7 +408,7 @@ TEST(QueryPlan, DeleteReturn) {
auto results = CollectProduce(produce.get(), symbol_table, *dba);
EXPECT_EQ(4, results.size());
dba->advance_command();
EXPECT_EQ(0, CountIterable(dba->vertices()));
EXPECT_EQ(0, CountIterable(dba->vertices(false)));
}
TEST(QueryPlan, DeleteNull) {
@ -490,8 +490,8 @@ TEST(QueryPlan, SetProperty) {
EXPECT_EQ(2, PullAll(set_r_p, *dba, symbol_table));
dba->advance_command();
EXPECT_EQ(CountIterable(dba->edges()), 2);
for (EdgeAccessor edge : dba->edges()) {
EXPECT_EQ(CountIterable(dba->edges(false)), 2);
for (EdgeAccessor edge : dba->edges(false)) {
ASSERT_EQ(edge.PropsAt(prop1).type(), PropertyValue::Type::Int);
EXPECT_EQ(edge.PropsAt(prop1).Value<int64_t>(), 42);
VertexAccessor from = edge.from();
@ -542,8 +542,8 @@ TEST(QueryPlan, SetProperties) {
EXPECT_EQ(1, PullAll(set_m_to_r, *dba, symbol_table));
dba->advance_command();
EXPECT_EQ(CountIterable(dba->edges()), 1);
for (EdgeAccessor edge : dba->edges()) {
EXPECT_EQ(CountIterable(dba->edges(false)), 1);
for (EdgeAccessor edge : dba->edges(false)) {
VertexAccessor from = edge.from();
EXPECT_EQ(from.Properties().size(), update ? 2 : 1);
if (update) {
@ -591,7 +591,7 @@ TEST(QueryPlan, SetLabels) {
n.op_, n.sym_, std::vector<GraphDbTypes::Label>{label2, label3});
EXPECT_EQ(2, PullAll(label_set, *dba, symbol_table));
for (VertexAccessor vertex : dba->vertices()) {
for (VertexAccessor vertex : dba->vertices(false)) {
vertex.SwitchNew();
EXPECT_EQ(3, vertex.labels().size());
EXPECT_TRUE(vertex.has_label(label2));
@ -640,8 +640,8 @@ TEST(QueryPlan, RemoveProperty) {
EXPECT_EQ(2, PullAll(set_r_p, *dba, symbol_table));
dba->advance_command();
EXPECT_EQ(CountIterable(dba->edges()), 2);
for (EdgeAccessor edge : dba->edges()) {
EXPECT_EQ(CountIterable(dba->edges(false)), 2);
for (EdgeAccessor edge : dba->edges(false)) {
EXPECT_EQ(edge.PropsAt(prop1).type(), PropertyValue::Type::Null);
VertexAccessor from = edge.from();
VertexAccessor to = edge.to();
@ -675,7 +675,7 @@ TEST(QueryPlan, RemoveLabels) {
n.op_, n.sym_, std::vector<GraphDbTypes::Label>{label1, label2});
EXPECT_EQ(2, PullAll(label_remove, *dba, symbol_table));
for (VertexAccessor vertex : dba->vertices()) {
for (VertexAccessor vertex : dba->vertices(false)) {
vertex.SwitchNew();
EXPECT_EQ(1, vertex.labels().size());
EXPECT_FALSE(vertex.has_label(label1));
@ -847,10 +847,10 @@ TEST(QueryPlan, MergeNoInput) {
auto create = std::make_shared<CreateNode>(node, nullptr);
auto merge = std::make_shared<plan::Merge>(nullptr, create, create);
EXPECT_EQ(0, CountIterable(dba->vertices()));
EXPECT_EQ(0, CountIterable(dba->vertices(false)));
EXPECT_EQ(1, PullAll(merge, *dba, symbol_table));
dba->advance_command();
EXPECT_EQ(1, CountIterable(dba->vertices()));
EXPECT_EQ(1, CountIterable(dba->vertices(false)));
}
TEST(QueryPlan, SetPropertyOnNull) {
@ -881,7 +881,7 @@ TEST(QueryPlan, SetPropertiesOnNull) {
std::vector<Symbol>{n.sym_});
auto set_op = std::make_shared<plan::SetProperties>(
optional, n.sym_, n_ident, plan::SetProperties::Op::REPLACE);
EXPECT_EQ(0, CountIterable(dba->vertices()));
EXPECT_EQ(0, CountIterable(dba->vertices(false)));
EXPECT_EQ(1, PullAll(set_op, *dba, symbol_table));
}
@ -899,7 +899,7 @@ TEST(QueryPlan, SetLabelsOnNull) {
std::vector<Symbol>{n.sym_});
auto set_op = std::make_shared<plan::SetLabels>(
optional, n.sym_, std::vector<GraphDbTypes::Label>{label});
EXPECT_EQ(0, CountIterable(dba->vertices()));
EXPECT_EQ(0, CountIterable(dba->vertices(false)));
EXPECT_EQ(1, PullAll(set_op, *dba, symbol_table));
}
@ -931,6 +931,6 @@ TEST(QueryPlan, RemoveLabelsOnNull) {
std::vector<Symbol>{n.sym_});
auto remove_op = std::make_shared<plan::RemoveLabels>(
optional, n.sym_, std::vector<GraphDbTypes::Label>{label});
EXPECT_EQ(0, CountIterable(dba->vertices()));
EXPECT_EQ(0, CountIterable(dba->vertices(false)));
EXPECT_EQ(1, PullAll(remove_op, *dba, symbol_table));
}

View File

@ -387,8 +387,8 @@ TEST(QueryPlan, OptionalMatchThenExpandToMissingNode) {
auto edge_type = dba->edge_type("edge_type");
dba->insert_edge(v1, v2, edge_type);
dba->advance_command();
EXPECT_EQ(2, CountIterable(dba->vertices()));
EXPECT_EQ(1, CountIterable(dba->edges()));
EXPECT_EQ(2, CountIterable(dba->vertices(false)));
EXPECT_EQ(1, CountIterable(dba->edges(false)));
AstTreeStorage storage;
SymbolTable symbol_table;
// OPTIONAL MATCH (n :missing)
@ -434,8 +434,8 @@ TEST(QueryPlan, OptionalMatchThenExpandToMissingEdge) {
auto edge_type = dba->edge_type("edge_type");
dba->insert_edge(v1, v2, edge_type);
dba->advance_command();
EXPECT_EQ(2, CountIterable(dba->vertices()));
EXPECT_EQ(1, CountIterable(dba->edges()));
EXPECT_EQ(2, CountIterable(dba->vertices(false)));
EXPECT_EQ(1, CountIterable(dba->edges(false)));
AstTreeStorage storage;
SymbolTable symbol_table;
// OPTIONAL MATCH (n :missing) -[r]- (m)
@ -816,7 +816,7 @@ TEST(QueryPlan, ScanAllByLabel) {
labeled_vertex.add_label(label);
dba->insert_vertex();
dba->advance_command();
EXPECT_EQ(2, CountIterable(dba->vertices()));
EXPECT_EQ(2, CountIterable(dba->vertices(false)));
// MATCH (n :label)
AstTreeStorage storage;
SymbolTable symbol_table;

View File

@ -92,7 +92,7 @@ TEST(RecordAccessor, SwitchOldAndSwitchNewMemberFunctionTest) {
// test both Switches work on existing record
{
auto dba = dbms.active();
auto v1 = *dba->vertices().begin();
auto v1 = *dba->vertices(false).begin();
v1.SwitchOld();
v1.SwitchNew();
}
@ -101,11 +101,11 @@ TEST(RecordAccessor, SwitchOldAndSwitchNewMemberFunctionTest) {
{
auto dba = dbms.active();
auto label = dba->label("label");
auto v1 = *dba->vertices().begin();
auto v1 = *dba->vertices(false).begin();
EXPECT_FALSE(v1.has_label(label)); // old record
v1.add_label(label); // modifying data does not switch to new
EXPECT_FALSE(v1.has_label(label)); // old record
EXPECT_FALSE(v1.has_label(label)); // old record
v1.add_label(label); // modifying data does not switch to new
EXPECT_FALSE(v1.has_label(label)); // old record
v1.SwitchNew();
EXPECT_TRUE(v1.has_label(label));
v1.SwitchOld();
@ -128,13 +128,13 @@ TEST(RecordAccessor, Reconstruct) {
// ensure we don't have label set
auto dba = dbms.active();
auto v1 = *dba->vertices().begin();
auto v1 = *dba->vertices(false).begin();
v1.SwitchNew();
EXPECT_FALSE(v1.has_label(label));
{
// update the record through a different accessor
auto v1_other_accessor = *dba->vertices().begin();
auto v1_other_accessor = *dba->vertices(false).begin();
v1_other_accessor.add_label(label);
EXPECT_FALSE(v1.has_label(label));
v1_other_accessor.SwitchNew();

View File

@ -0,0 +1,40 @@
#include <algorithm>
#include <iterator>
#include <vector>
#include "gtest/gtest.h"
#include "data_structures/concurrent/skiplist.hpp"
#include "database/indexes/index_common.hpp"
template <class TIterable>
int Count(TIterable &collection) {
int ret = 0;
for (__attribute__((unused)) auto it : collection) ret += 1;
return ret;
}
TEST(SkipListSuffix, EmptyRange) {
SkipList<int> V;
auto access = V.access();
auto r1 = IndexUtils::SkipListSuffix<typename SkipList<int>::Iterator, int>(
access.begin(), std::move(access));
EXPECT_EQ(Count(r1), 0);
}
TEST(SkipListSuffix, NonEmptyRange) {
SkipList<int> V;
auto access = V.access();
access.insert(1);
access.insert(5);
access.insert(3);
auto r1 = IndexUtils::SkipListSuffix<typename SkipList<int>::Iterator, int>(
access.begin(), std::move(access));
EXPECT_EQ(Count(r1), 3);
auto iter = r1.begin();
EXPECT_EQ(*iter, 1);
++iter;
EXPECT_EQ(*iter, 3);
++iter;
EXPECT_EQ(*iter, 5);
}