Added support for some queries.

This commit is contained in:
Kruno Tomola Fabro 2016-08-30 08:53:02 +01:00
parent 027dce0d9a
commit 0f249c4f1f
16 changed files with 428 additions and 33 deletions

View File

@ -145,7 +145,7 @@ public:
VertexAccessor update() const;
bool remove() const;
void remove() const;
const Property &at(VertexPropertyFamily &key) const;
@ -204,7 +204,7 @@ public:
EdgeAccessor update() const;
bool remove() const;
void remove() const;
const Property &at(EdgePropertyFamily &key) const;

View File

@ -178,12 +178,11 @@ public:
return remove(record, t), true;
}
bool remove(T *record, tx::Transaction &t)
void remove(T *record, tx::Transaction &t)
{
assert(record != nullptr);
lock_and_validate(record, t);
record->mark_deleted(t);
return true;
}
const Id id;

View File

@ -271,13 +271,111 @@ auto load_queries(Db &db)
DbAccessor t(db);
auto &type = t.type_find_or_create("TYPE");
auto prop_name = t.vertex_property_key("name", args[0]->flags);
auto it_type = type.index().for_range(t);
auto it_vertex = t.vertex_access();
Option<const EdgeAccessor> r;
// TODO
// if (it_type.count().max > it_vertex.count().max) {
// }
auto it_type = type.index()
.for_range(t)
.clone_to(r) // Savepoint
.from() // Backtracing
.has_property(prop_name, *args[0].get())
.replace(r); // Load savepoint
auto it_vertex = t.vertex_access()
.fill()
.has_property(prop_name, *args[0].get())
.out()
.type(type);
if (it_type.count() > it_vertex.count()) {
// Going through vertices wiil probably be faster
it_vertex.to().for_all([&](auto m) {
// PRINT m
});
} else {
// Going through edges wiil probably be faster
it_type.to().for_all([&](auto m) {
// PRINT m
});
}
return t.commit();
};
// MATCH (n)-[:TYPE]->(m) WHERE n.name = "kruno" RETURN n,m
auto match_name_type_return_cross = [&db](const properties_t &args) {
DbAccessor t(db);
auto &type = t.type_find_or_create("TYPE");
auto prop_name = t.vertex_property_key("name", args[0]->flags);
Option<const VertexAccessor> n;
Option<const EdgeAccessor> r;
auto it_type = type.index()
.for_range(t)
.clone_to(r) // Savepoint
.from() // Backtracing
.has_property(prop_name, *args[0].get())
.clone_to(n) // Savepoint
.replace(r); // Load savepoint
auto it_vertex = t.vertex_access()
.fill()
.has_property(prop_name, *args[0].get())
.clone_to(n) // Savepoint
.out()
.type(type);
if (it_type.count() > it_vertex.count()) {
// Going through vertices wiil probably be faster
it_vertex.to().for_all([&](auto m) {
// PRINT n,m
});
} else {
// Going through edges wiil probably be faster
it_type.to().for_all([&](auto m) {
// PRINT n,m
});
}
return t.commit();
};
// MATCH (n:LABEL)-[:TYPE]->(m) RETURN n
auto match_label_type_return = [&db](const properties_t &args) {
DbAccessor t(db);
auto &type = t.type_find_or_create("TYPE");
auto &label = t.label_find_or_create("LABEL");
Option<const VertexAccessor> bt;
auto it_type = type.index().for_range(t).from().label(label);
auto it_vertex = t.vertex_access()
.fill()
.label(label)
.clone_to(bt) // Savepoint
.out()
.type(type)
.replace(bt); // Load savepoint
if (it_type.count() > it_vertex.count()) {
// Going through vertices wiil probably be faster
it_vertex.for_all([&](auto n) {
// PRINT n
});
} else {
// Going through edges wiil probably be faster
it_type.for_all([&](auto n) {
// PRINT n
});
}
return t.commit();
};
@ -307,6 +405,9 @@ auto load_queries(Db &db)
queries[14897166600223619735u] = match_edge_all_delete;
queries[16888549834923624215u] = match_edge_type_delete;
queries[11675960684124428508u] = match_id_type_return;
queries[1554436524951961398u] = match_name_type_return;
queries[8537338362659537296u] = match_name_type_return_cross;
queries[8918221081398321263u] = match_label_type_return;
return queries;
}

View File

@ -15,19 +15,23 @@ class Edges;
// There exists circular dependecy with VertexAccessor.
class EdgeAccessor : public RecordAccessor<TypeGroupEdge, EdgeAccessor>
{
friend VertexAccessor;
public:
using RecordAccessor::RecordAccessor;
typedef Edge record_t;
typedef EdgeRecord record_list_t;
// Removes self and disconects vertices from it.
bool remove() const;
void remove() const;
void edge_type(EdgeType const &edge_type);
const EdgeType &edge_type() const;
// EdgeAccessor doesnt need to be filled
VertexAccessor from() const;
// EdgeAccessor doesnt need to be filled
VertexAccessor to() const;
};

View File

@ -146,7 +146,7 @@ public:
}
protected:
bool remove() const;
void remove() const;
T *record{nullptr};
vlist_t *const vlist;

View File

@ -17,8 +17,8 @@ public:
typedef Vertex record_t;
typedef VertexRecord record_list_t;
// Removes only self.
bool remove() const { return RecordAccessor::remove(); }
// Removes self and all edges connected to it.
void remove() const;
size_t out_degree() const;

View File

@ -1,8 +1,10 @@
#pragma once
#include "utils/total_ordering.hpp"
// Represents number of to be returned elements from iterator. Where acutal
// number is probably somwhere in [min,max].
class Count
class Count : public TotalOrdering<Count>
{
public:
@ -16,6 +18,18 @@ public:
return *this;
}
size_t avg() const { return ((max - min) >> 1) + min; }
friend constexpr bool operator<(const Count &lhs, const Count &rhs)
{
return lhs.avg() < rhs.avg();
}
friend constexpr bool operator==(const Count &lhs, const Count &rhs)
{
return lhs.avg() == rhs.avg();
}
size_t min;
size_t max;
};

View File

@ -0,0 +1,77 @@
#pragma once
namespace iter
{
// Class which maps values returned by I iterator into iterators of type J
// ,which
// return value of type T, with function OP.
// function.
// T - type of return value
// I - iterator type
// J - iterator type returned from OP
// OP - type of mapper function
template <class T, class I, class J, class OP>
class FlatMap : public IteratorBase<T>
{
public:
FlatMap() = delete;
// FlatMap operation is designed to be used in chained calls which operate
// on a
// iterator. FlatMap will in that usecase receive other iterator by value
// and
// std::move is a optimization for it.
FlatMap(I &&iter, OP &&op) : iter(std::move(iter)), op(std::move(op)) {}
FlatMap(FlatMap &&m)
: iter(std::move(m.iter)), op(std::move(m.op)),
sub_iter(std::move(m.sub_iter))
{
}
~FlatMap() final {}
Option<T> next() final
{
do {
if (!sub_iter.is_present()) {
auto item = iter.next();
if (item.is_present()) {
sub_iter = Option<J>(op(item.take()));
} else {
return Option<T>();
}
}
auto item = sub_iter.get().next();
if (item.is_present()) {
return std::move(item);
} else {
sub_iter.take();
}
} while (true);
}
Count count() final
{
// TODO: Correct count, are at least correcter
return iter.count();
}
private:
I iter;
Option<J> sub_iter;
OP op;
};
template <class I, class OP>
auto make_flat_map(I &&iter, OP &&op)
{
// Compiler cant deduce type T and J. decltype is here to help with it.
return FlatMap<decltype(op(iter.next().take()).next().take()), I,
decltype(op(iter.next().take())), OP>(std::move(iter),
std::move(op));
}
}

View File

@ -0,0 +1,58 @@
#pragma once
#include "utils/iterator/iterator_base.hpp"
#include "utils/option.hpp"
namespace iter
{
// Class which inspects values returned by I iterator before passing thenm as
// result.
// function.
// T - type of return value
// I - iterator type
// OP - type of inspector function. OP: T&->void
template <class T, class I, class OP>
class Inspect : public IteratorBase<T>
{
public:
Inspect() = delete;
// Inspect operation is designed to be used in chained calls which operate
// on a
// iterator. Inspect will in that usecase receive other iterator by value
// and
// std::move is a optimization for it.
Inspect(I &&iter, OP &&op) : iter(std::move(iter)), op(std::move(op)) {}
Inspect(Inspect &&m) : iter(std::move(m.iter)), op(std::move(m.op)) {}
~Inspect() final {}
Option<T> next() final
{
auto item = iter.next();
if (item.is_present()) {
op(item.get());
return std::move(item);
} else {
return Option<T>();
}
}
Count count() final { return iter.count(); }
private:
I iter;
OP op;
};
template <class I, class OP>
auto make_inspect(I &&iter, OP &&op)
{
// Compiler cant deduce type T. decltype is here to help with it.
return Inspect<decltype(iter.next().take()), I, OP>(std::move(iter),
std::move(op));
}
}

View File

@ -3,9 +3,12 @@
#include "utils/iterator/accessor.hpp"
#include "utils/iterator/count.hpp"
#include "utils/iterator/filter.hpp"
#include "utils/iterator/flat_map.hpp"
#include "utils/iterator/for_all.hpp"
#include "utils/iterator/inspect.hpp"
#include "utils/iterator/iterator_accessor.hpp"
#include "utils/iterator/iterator_base.hpp"
#include "utils/iterator/lambda_iterator.hpp"
#include "utils/iterator/limited_map.hpp"
#include "utils/iterator/map.hpp"
#include "utils/iterator/range_iterator.hpp"

View File

@ -15,6 +15,15 @@ auto make_filter(I &&iter, OP &&op);
template <class I, class C>
void for_all(I &&iter, C &&consumer);
template <class I, class OP>
auto make_flat_map(I &&iter, OP &&op);
template <class I, class OP>
auto make_inspect(I &&iter, OP &&op);
template <class I, class OP>
auto make_limited_map(I &&iter, OP &&op);
}
// Base iterator for next() kind iterator.
@ -43,12 +52,64 @@ public:
std::move(*this), std::move(op));
}
// Replaces every item with item taken from n if it exists.
template <class R>
auto replace(Option<R> &n)
{
return iter::make_limited_map<decltype(std::move(*this))>(
std::move(*this), [&](auto v) mutable { return std::move(n); });
}
// Maps with call to method to() and filters with call to fill.
auto to()
{
return map([](auto er) { return er.to(); }).fill();
}
// Maps with call to method from() and filters with call to fill.
auto from()
{
return map([](auto er) { return er.from(); }).fill();
}
// Combines out iterators into one iterator.
auto out()
{
return iter::make_flat_map<decltype(std::move(*this))>(
std::move(*this), [](auto vr) { return vr.out().fill(); });
}
// Filters with label on from vertex.
template <class LABEL>
auto from_label(LABEL const &label)
{
return filter([&](auto &ra) {
auto va = ra.from();
return va.fill() && va.has_label(label);
});
}
// Filters with property under given key
template <class KEY, class PROP>
auto has_property(KEY &key, PROP const &prop)
{
return filter([&](auto &va) { return va.at(key) == prop; });
}
// Copy-s all pasing value to t before they are returned.
// auto clone_to(Option<T> &t)
// {
// return iter::make_inspect<decltype(std::move(*this))>(
// std::move(*this), [&](auto &v) { t = Option<T>(v); });
// }
// Copy-s pasing value to t before they are returned.
auto clone_to(Option<const T> &t)
{
return iter::make_inspect<decltype(std::move(*this))>(
std::move(*this), [&](auto &v) mutable { t = Option<const T>(v); });
}
// Filters with call to method fill()
auto fill()
{
@ -62,6 +123,13 @@ public:
return filter([&](auto &ra) { return ra.edge_type() == type; });
}
// Filters with label.
template <class LABEL>
auto label(LABEL const &label)
{
return filter([&](auto &va) { return va.has_label(label); });
}
// Filters out vertices which are connected.
auto isolated()
{

View File

@ -0,0 +1,56 @@
#pragma once
#include "utils/iterator/iterator_base.hpp"
#include "utils/option.hpp"
namespace iter
{
// Class which maps values returned by I iterator into value of type T with OP
// function and ends when op return empty optional.
// T - type of return value
// I - iterator type
// OP - type of mapper function. OP: V -> Option<T>
template <class T, class I, class OP>
class LimitedMap : public IteratorBase<T>
{
public:
LimitedMap() = delete;
// LimitedMap operation is designed to be used in chained calls which
// operate on a
// iterator. LimitedMap will in that usecase receive other iterator by value
// and
// std::move is a optimization for it.
LimitedMap(I &&iter, OP &&op) : iter(std::move(iter)), op(std::move(op)) {}
LimitedMap(LimitedMap &&m) : iter(std::move(m.iter)), op(std::move(m.op)) {}
~LimitedMap() final {}
Option<T> next() final
{
auto item = iter.next();
if (item.is_present()) {
return op(item.take());
} else {
return Option<T>();
}
}
Count count() final { return iter.count(); }
private:
I iter;
OP op;
};
template <class I, class OP>
auto make_limited_map(I &&iter, OP &&op)
{
// Compiler cant deduce type T. decltype is here to help with it.
return LimitedMap<decltype(op(iter.next().take()).take()), I, OP>(
std::move(iter), std::move(op));
}
}

View File

@ -282,7 +282,7 @@ const Id &VertexAccessor::id() const { return HALF_CALL(id()); }
VertexAccessor VertexAccessor::update() const { return CALL(update()); }
bool VertexAccessor::remove() const { return HALF_CALL(remove()); }
void VertexAccessor::remove() const { HALF_CALL(remove()); }
const Property &VertexAccessor::at(VertexPropertyFamily &key) const
{
@ -372,7 +372,7 @@ const Id &EdgeAccessor::id() const { return HALF_CALL(id()); }
EdgeAccessor EdgeAccessor::update() const { return CALL(update()); }
bool EdgeAccessor::remove() const { return HALF_CALL(remove()); }
void EdgeAccessor::remove() const { HALF_CALL(remove()); }
const Property &EdgeAccessor::at(EdgePropertyFamily &key) const
{

View File

@ -2,24 +2,19 @@
#include "storage/vertex_record.hpp"
bool EdgeAccessor::remove() const
void EdgeAccessor::remove() const
{
if (RecordAccessor::remove()) {
auto from_v = from();
bool f_from = from_v.fill();
assert(f_from);
RecordAccessor::remove();
auto from_v = from();
bool f_from = from_v.fill();
assert(f_from);
auto to_v = to();
bool f_to = to_v.fill();
assert(f_to);
auto to_v = to();
bool f_to = to_v.fill();
assert(f_to);
from_v.update().record->data.out.remove(vlist);
to_v.update().record->data.in.remove(vlist);
return true;
} else {
return false;
}
from_v.update().record->data.out.remove(vlist);
to_v.update().record->data.in.remove(vlist);
}
void EdgeAccessor::edge_type(const EdgeType &edge_type)

View File

@ -13,11 +13,11 @@
// }
template <class T, class Derived>
bool RecordAccessor<T, Derived>::remove() const
void RecordAccessor<T, Derived>::remove() const
{
assert(!empty());
return vlist->remove(record, db.trans);
vlist->remove(record, db.trans);
}
template class RecordAccessor<TypeGroupEdge, EdgeAccessor>;

View File

@ -48,3 +48,23 @@ bool VertexAccessor::in_contains(VertexAccessor const &other) const
{
return record->data.in.contains(other.vlist);
}
void VertexAccessor::remove() const
{
RecordAccessor::remove();
for (auto evr : record->data.out) {
auto ea = EdgeAccessor(evr, db);
ea.vlist->remove(db.trans);
auto to_v = ea.to();
to_v.fill();
to_v.update().record->data.in.remove(ea.vlist);
}
for (auto evr : record->data.in) {
auto ea = EdgeAccessor(evr, db);
ea.vlist->remove(db.trans);
auto from_v = ea.from();
from_v.fill();
from_v.update().record->data.out.remove(ea.vlist);
}
}