Added support for some queries.
This commit is contained in:
parent
027dce0d9a
commit
0f249c4f1f
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -146,7 +146,7 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
bool remove() const;
|
||||
void remove() const;
|
||||
|
||||
T *record{nullptr};
|
||||
vlist_t *const vlist;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
77
include/utils/iterator/flat_map.hpp
Normal file
77
include/utils/iterator/flat_map.hpp
Normal 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));
|
||||
}
|
||||
}
|
58
include/utils/iterator/inspect.hpp
Normal file
58
include/utils/iterator/inspect.hpp
Normal 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));
|
||||
}
|
||||
}
|
@ -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"
|
||||
|
@ -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()
|
||||
{
|
||||
|
56
include/utils/iterator/limited_map.hpp
Normal file
56
include/utils/iterator/limited_map.hpp
Normal 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));
|
||||
}
|
||||
}
|
@ -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
|
||||
{
|
||||
|
@ -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)
|
||||
|
@ -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>;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user