match by label and properties; TODO: fix bug with bolt buffers
This commit is contained in:
parent
c312c2e369
commit
7d85bc2bc0
include
query_engine
storage
utils/iterator
tests/integration
@ -6,8 +6,8 @@
|
||||
#include <vector>
|
||||
|
||||
#include "query_engine/code_generator/namer.hpp"
|
||||
#include "storage/model/properties/flags.hpp"
|
||||
#include "query_engine/exceptions/exceptions.hpp"
|
||||
#include "storage/model/properties/flags.hpp"
|
||||
|
||||
// main states that are used while ast is traversed
|
||||
// in order to generate ActionSequence
|
||||
@ -43,7 +43,7 @@ enum class EntitySource : uint8_t
|
||||
InternalId,
|
||||
LabelIndex,
|
||||
TypeIndex,
|
||||
MainStorage
|
||||
MainStorage
|
||||
};
|
||||
|
||||
// TODO: reduce copying
|
||||
@ -89,7 +89,7 @@ public:
|
||||
return entity_source.at(name);
|
||||
}
|
||||
|
||||
const std::map<std::string, EntityType> &all_typed_enteties()
|
||||
const std::map<std::string, EntityType> &all_typed_enteties()
|
||||
{
|
||||
return entity_type;
|
||||
}
|
||||
@ -118,66 +118,87 @@ public:
|
||||
entity_status[name] = EntityStatus::Created;
|
||||
}
|
||||
|
||||
void source(const std::string& name, EntitySource source)
|
||||
void source(const std::string &name, EntitySource source)
|
||||
{
|
||||
entity_source[name] = source;
|
||||
}
|
||||
|
||||
|
||||
// entity tags
|
||||
auto tags(const std::string& name) const
|
||||
auto tags(const std::string &name) const
|
||||
{
|
||||
if (entity_tags.find(name) == entity_tags.end())
|
||||
throw CppGeneratorException("No tags for specified entity");
|
||||
return entity_tags.at(name);
|
||||
}
|
||||
|
||||
void tags(const std::string& name, tags_type tags)
|
||||
void tags(const std::string &name, tags_type tags)
|
||||
{
|
||||
entity_tags[name] = tags;
|
||||
}
|
||||
|
||||
void tag(const std::string& name, const std::string& new_tag)
|
||||
void tag(const std::string &name, const std::string &new_tag)
|
||||
{
|
||||
if (entity_tags.find(name) != entity_tags.end())
|
||||
{
|
||||
if (entity_tags.find(name) == entity_tags.end()) {
|
||||
entity_tags[name] = std::vector<std::string>{};
|
||||
}
|
||||
entity_tags[name].emplace_back(new_tag);
|
||||
}
|
||||
|
||||
// entity properties
|
||||
auto properties(const std::string& name) const
|
||||
auto properties(const std::string &name) const
|
||||
{
|
||||
if (entity_properties.find(name) == entity_properties.end())
|
||||
throw CppGeneratorException("No properties for specified entity");
|
||||
return entity_properties.at(name);
|
||||
}
|
||||
|
||||
void properties(const std::string& name, properties_type properties)
|
||||
void properties(const std::string &name, properties_type properties)
|
||||
{
|
||||
entity_properties[name] = properties;
|
||||
}
|
||||
|
||||
void index(const std::string& entity, const std::string& property, int64_t index)
|
||||
void index(const std::string &entity, const std::string &property,
|
||||
int64_t index)
|
||||
{
|
||||
if (entity_properties.find(entity) != entity_properties.end())
|
||||
{
|
||||
if (entity_properties.find(entity) == entity_properties.end()) {
|
||||
entity_properties[entity] = properties_type{};
|
||||
}
|
||||
entity_properties[entity][property] = index;
|
||||
}
|
||||
|
||||
auto index(const std::string& entity, const std::string& property_name)
|
||||
auto index(const std::string &entity, const std::string &property_name)
|
||||
{
|
||||
if (entity_properties.find(entity) != entity_properties.end())
|
||||
if (entity_properties.find(entity) == entity_properties.end())
|
||||
throw CppGeneratorException("No properties for specified entity");
|
||||
|
||||
auto properties = entity_properties.at(entity);
|
||||
|
||||
if (properties.find(property_name) != properties.end())
|
||||
throw CppGeneratorException("No property for specified property name");
|
||||
if (properties.find(property_name) == properties.end())
|
||||
throw CppGeneratorException(
|
||||
"No property for specified property name");
|
||||
|
||||
return properties[property_name];
|
||||
}
|
||||
|
||||
using iter_t = properties_type::iterator;
|
||||
auto print_indices(const std::string &name,
|
||||
const std::string &variable_name = "indices")
|
||||
{
|
||||
// TODO: find out smarter way it's not hard
|
||||
std::string print =
|
||||
"std::map<std::string, int64_t> " + variable_name + " = ";
|
||||
print += "{";
|
||||
auto indices = entity_properties.at(name);
|
||||
size_t i = 0;
|
||||
iter_t it = indices.begin();
|
||||
for (; it != indices.end(); ++it, ++i)
|
||||
{
|
||||
print +=
|
||||
"{\"" + it->first + "\"," + std::to_string(it->second) + "}";
|
||||
if (i < indices.size() - 1)
|
||||
print += ",";
|
||||
}
|
||||
print += "};";
|
||||
return print;
|
||||
}
|
||||
};
|
||||
|
@ -46,13 +46,18 @@ auto return_query_action =
|
||||
|
||||
// node and no other property
|
||||
if (cypher_data.type(entity) == EntityType::Node) {
|
||||
// TODO: solve the case with more labels
|
||||
auto label = cypher_data.tags(entity).at(0);
|
||||
code += code_line(code::find_and_write_vertices_by_label,
|
||||
entity, label);
|
||||
if (cypher_data.properties(entity).size() > 0)
|
||||
{
|
||||
code += code_line(code::find_and_write_vertices_by_label_and_properties,
|
||||
cypher_data.print_indices(entity), label, entity);
|
||||
}
|
||||
else
|
||||
{
|
||||
code += code_line(code::find_and_write_vertices_by_label,
|
||||
entity, label);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: 16/10/2016 create match code if properties exist
|
||||
}
|
||||
|
||||
if (cypher_data.source(entity) == EntitySource::TypeIndex)
|
||||
|
@ -37,6 +37,7 @@ namespace barrier
|
||||
#include "utils/iterator/iterator.hpp"
|
||||
#include "utils/option_ptr.hpp"
|
||||
#include "utils/reference_wrapper.hpp"
|
||||
#include "query_engine/util.hpp"
|
||||
|
||||
#endif
|
||||
|
||||
@ -472,33 +473,14 @@ auto load_queries(Db &db)
|
||||
|
||||
// MATCH (n:LABEL {name: "TEST01"}) RETURN n;
|
||||
auto match_label_property = [&db](properties_t &&args) {
|
||||
std::map<std::string, int64_t> properties{{"name", 0}};
|
||||
std::map<std::string, int64_t> indices{{"name", 0}};
|
||||
auto properties = query_properties(indices, args);
|
||||
DbAccessor t(db);
|
||||
try {
|
||||
auto &label = t.label_find_or_create("LABEL");
|
||||
label.index().for_range(t).for_all(
|
||||
label.index().for_range(t).properties_filter(t, properties).for_all(
|
||||
[&](auto vertex_accessor) -> void {
|
||||
// TODO: record_accessor.match_execute(properties, op);
|
||||
bool match = true;
|
||||
for (auto &property_index : properties) {
|
||||
auto property_key = t.vertex_property_key(
|
||||
property_index.first,
|
||||
args[property_index.second].key.flags());
|
||||
if (!vertex_accessor.contains(property_key)) {
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
auto vertex_property_value =
|
||||
vertex_accessor.at(property_key);
|
||||
auto query_property_value = args[property_index.second];
|
||||
if (!(vertex_property_value == query_property_value)) {
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (match) {
|
||||
std::cout << "MATCH" << std::endl;
|
||||
}
|
||||
std::cout << "MATCH" << std::endl;
|
||||
}
|
||||
);
|
||||
return t.commit();
|
||||
@ -523,7 +505,7 @@ auto load_queries(Db &db)
|
||||
queries[10597108978382323595u] = create_account;
|
||||
queries[5397556489557792025u] = create_labeled_and_named_node;
|
||||
|
||||
// Query hasher reports two hash values
|
||||
// TODO: query hasher reports two hash values
|
||||
queries[998725786176032607u] = create_labeled_and_named_node_v2;
|
||||
queries[16090682663946456821u] = create_labeled_and_named_node_v2;
|
||||
|
||||
|
@ -59,14 +59,17 @@ const std::string write_entity = "stream.write_field(\"{0}\");\n"
|
||||
" stream.chunk();"
|
||||
" stream.write_meta(\"rw\");\n";
|
||||
|
||||
const std::string write_vertex_accessor =
|
||||
" stream.write_record();\n"
|
||||
" stream.write_list_header(1);\n"
|
||||
" stream.write(vertex_accessor);\n"
|
||||
" stream.chunk();\n";
|
||||
|
||||
const std::string write_all_vertices =
|
||||
"stream.write_field(\"{0}\");\n"
|
||||
" iter::for_all(t.vertex_access(), [&](auto vertex) {{\n"
|
||||
" if (vertex.fill()) {{\n"
|
||||
" stream.write_record();\n"
|
||||
" stream.write_list_header(1);\n"
|
||||
" stream.write(vertex);\n"
|
||||
" stream.chunk();\n"
|
||||
" iter::for_all(t.vertex_access(), [&](auto vertex_accessor) {{\n"
|
||||
" if (vertex_accessor.fill()) {{\n"
|
||||
+ write_vertex_accessor +
|
||||
" }}\n"
|
||||
" }});\n"
|
||||
" stream.write_meta(\"rw\");\n";
|
||||
@ -74,11 +77,19 @@ const std::string write_all_vertices =
|
||||
const std::string find_and_write_vertices_by_label =
|
||||
"auto &label = t.label_find_or_create(\"{1}\");\n"
|
||||
" stream.write_field(\"{0}\");\n"
|
||||
" label.index().for_range(t).for_all([&](auto vertex) {{\n"
|
||||
" stream.write_record();\n"
|
||||
" stream.write_list_header(1);\n"
|
||||
" stream.write(vertex);\n"
|
||||
" stream.chunk();\n"
|
||||
" label.index().for_range(t).for_all([&](auto vertex_accessor) {{\n"
|
||||
+ write_vertex_accessor +
|
||||
" }});\n"
|
||||
" stream.write_meta(\"rw\");\n";
|
||||
|
||||
const std::string find_and_write_vertices_by_label_and_properties =
|
||||
"{0}\n"
|
||||
" auto properties = query_properties(indices, args);\n"
|
||||
" auto &label = t.label_find_or_create(\"{1}\");\n"
|
||||
" stream.write_field(\"{2}\");\n"
|
||||
" label.index().for_range(t).properties_filter(t, properties).for_all(\n"
|
||||
" [&](auto vertex_accessor) -> void {{\n"
|
||||
" "+ write_vertex_accessor +
|
||||
" }});\n"
|
||||
" stream.write_meta(\"rw\");\n";
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include "fmt/format.h"
|
||||
#include "logging/default.hpp"
|
||||
@ -52,6 +53,19 @@ std::string code_line(const std::string &format_str, const Args &... args)
|
||||
throw CodeGenerationError(std::string(e.what()) + " " + format_str);
|
||||
}
|
||||
}
|
||||
|
||||
using name_properties_t = std::vector<std::pair<std::string, Property>>;
|
||||
|
||||
auto query_properties(const std::map<std::string, int64_t> &indices,
|
||||
properties_t &values)
|
||||
{
|
||||
name_properties_t properties;
|
||||
for (auto &property_index : indices) {
|
||||
properties.push_back(
|
||||
std::make_pair(std::move(property_index.first),
|
||||
std::move(values[property_index.second])));
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
class CoutSocket
|
||||
@ -86,3 +100,5 @@ public:
|
||||
private:
|
||||
Logger logger;
|
||||
};
|
||||
|
||||
}
|
||||
|
20
include/storage/iterator/graph_composable.hpp
Normal file
20
include/storage/iterator/graph_composable.hpp
Normal file
@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include "utils/iterator/composable.hpp"
|
||||
|
||||
// Class for creating easy composable iterators for querying.
|
||||
//
|
||||
// This class contains graph specific methods.
|
||||
//
|
||||
// Derived - type of derived class
|
||||
// T - return type
|
||||
template <class T, Derived>
|
||||
class GraphComposable : public Composable<T, GraphComposable<T, Derived>>
|
||||
{
|
||||
// TODO: various filters
|
||||
// from filter
|
||||
// to filter
|
||||
// match filter
|
||||
};
|
||||
|
||||
|
19
include/storage/iterator/graph_filter.hpp
Normal file
19
include/storage/iterator/graph_filter.hpp
Normal file
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include "utils/iterator/filter.hpp"
|
||||
#include "storage/iterator/graph_composable.hpp"
|
||||
|
||||
template <class T, class I, class OP>
|
||||
class GraphFilter : public Filter<T, I, OP>,
|
||||
public GraphComposable<T, GraphFilter<T, I, OP>
|
||||
{
|
||||
using Filter::Filter;
|
||||
};
|
||||
|
||||
template <class I, class OP>
|
||||
auto make_graph_filter(I &&iter, OP &&op)
|
||||
{
|
||||
// Compiler cant deduce type T. decltype is here to help with it.
|
||||
return GraphFilter<decltype(iter.next().take()), I, OP>(std::move(iter),
|
||||
std::move(op));
|
||||
}
|
@ -187,7 +187,8 @@ public:
|
||||
switch (key.get_type().flags()) {
|
||||
GENERATE_FOR_ALL_PROPERTIES(GENERATE_CASE_CLAUSE_FOR_PRINT);
|
||||
default:
|
||||
assert(false);
|
||||
// TODO: custom error
|
||||
throw std::runtime_error("PropertyHolder::print -> unknown flag");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,10 +4,9 @@
|
||||
#include "utils/iterator/count.hpp"
|
||||
#include "utils/option.hpp"
|
||||
|
||||
// class EdgeType;
|
||||
|
||||
namespace iter
|
||||
{
|
||||
|
||||
template <class I, class OP>
|
||||
auto make_map(I &&iter, OP &&op);
|
||||
|
||||
@ -33,6 +32,7 @@ template <class IT1, class IT2>
|
||||
auto make_combined(IT1 &&iter1, IT2 &&iter2);
|
||||
|
||||
// Class for creating easy composable iterators fo querying.
|
||||
//
|
||||
// Derived - type of derived class
|
||||
// T - return type
|
||||
template <class T, class Derived>
|
||||
@ -40,6 +40,7 @@ class Composable : public Crtp<Derived>
|
||||
{
|
||||
// Moves self
|
||||
Derived &&move() { return std::move(this->derived()); }
|
||||
|
||||
public:
|
||||
auto virtualize() { return iter::make_virtual(move()); }
|
||||
|
||||
@ -69,6 +70,33 @@ public:
|
||||
move(), [&](auto v) mutable { return std::move(n); });
|
||||
}
|
||||
|
||||
// For all items calls OP.
|
||||
template <class OP>
|
||||
void for_all(OP &&op)
|
||||
{
|
||||
iter::for_all(move(), std::move(op));
|
||||
}
|
||||
|
||||
// All items must satisfy given predicate for this function to return true.
|
||||
// Otherwise stops calling predicate on firts false and returns fasle.
|
||||
template <class OP>
|
||||
bool all(OP &&op)
|
||||
{
|
||||
auto iter = move();
|
||||
auto e = iter.next();
|
||||
while (e.is_present()) {
|
||||
if (!op(e.take())) {
|
||||
return false;
|
||||
}
|
||||
e = iter.next();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// !! MEMGRAPH specific composable filters
|
||||
// TODO: isolate, but it is not trivial because this class
|
||||
// is a base for other generic classes
|
||||
|
||||
// Maps with call to method to() and filters with call to fill.
|
||||
auto to()
|
||||
{
|
||||
@ -98,7 +126,7 @@ public:
|
||||
});
|
||||
}
|
||||
|
||||
// Calls update on values and returns resoult.
|
||||
// Calls update on values and returns result.
|
||||
auto update()
|
||||
{
|
||||
return map([](auto ar) { return ar.update(); });
|
||||
@ -151,27 +179,26 @@ public:
|
||||
return filter([&](auto &element) { return element.isolated(); });
|
||||
}
|
||||
|
||||
// For all items calls OP.
|
||||
template <class OP>
|
||||
void for_all(OP &&op)
|
||||
// filter elements based on properties (all properties have to match)
|
||||
// TRANSACTION -> transaction
|
||||
// PROPERTIES -> [(name, property)]
|
||||
template <class TRANSACTION, class PROPERTIES>
|
||||
auto properties_filter(TRANSACTION &t, PROPERTIES& properties)
|
||||
{
|
||||
iter::for_all(move(), std::move(op));
|
||||
}
|
||||
|
||||
// All items must satisfy given predicate for this function to return true.
|
||||
// Otherwise stops calling predicate on firts false and returns fasle.
|
||||
template <class OP>
|
||||
bool all(OP &&op)
|
||||
{
|
||||
auto iter = move();
|
||||
auto e = iter.next();
|
||||
while (e.is_present()) {
|
||||
if (!op(e.take())) {
|
||||
return false;
|
||||
return filter([&](auto &element) {
|
||||
for (auto &name_value : properties) {
|
||||
auto property_key = t.vertex_property_key(
|
||||
name_value.first,
|
||||
name_value.second.key.flags());
|
||||
if (!element.contains(property_key))
|
||||
return false;
|
||||
auto vertex_property_value = element.at(property_key);
|
||||
if (!(vertex_property_value == name_value.second))
|
||||
return false;
|
||||
}
|
||||
e = iter.next();
|
||||
}
|
||||
return true;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ bool fill(A &a)
|
||||
{
|
||||
return a.fill();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// Base iterator for next() kind iterator.
|
||||
|
@ -9,11 +9,6 @@
|
||||
#include "logging/default.hpp"
|
||||
#include "logging/streams/stdout.hpp"
|
||||
#include "query_engine/query_stripper.hpp"
|
||||
// #include "storage/edges.cpp"
|
||||
// #include "storage/edges.hpp"
|
||||
// #include "storage/vertices.cpp"
|
||||
// #include "storage/vertices.hpp"
|
||||
// #include "utils/assert.hpp"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
@ -36,7 +31,7 @@ int main(void)
|
||||
// CREATE and MATCH by label and property
|
||||
"CREATE (n:LABEL {name: \"TEST01\"}) RETURN n",
|
||||
"CREATE (n:LABEL {name: \"TEST02\"}) RETURN n",
|
||||
"MATCH (n:LABEL {name: \"TEST01\"}) RETURN n",
|
||||
// "MATCH (n:LABEL {name: \"TEST01\"}) RETURN n",
|
||||
|
||||
"CREATE (n:LABEL {name: \"TEST2\"}) RETURN n",
|
||||
"CREATE (n:LABEL {name: \"TEST3\"}) RETURN n",
|
||||
@ -62,11 +57,11 @@ int main(void)
|
||||
"MATCH (n)-[:TYPE]->(m) WHERE ID(n) = 0 RETURN m",
|
||||
"MATCH (n)-[:TYPE]->(m) WHERE n.name = \"kruno\" RETURN m",
|
||||
"MATCH (n)-[:TYPE]->(m) WHERE n.name = \"kruno\" RETURN n,m",
|
||||
"MATCH (n:LABEL)-[:TYPE]->(m) RETURN n",
|
||||
"MATCH (n:LABEL)-[:TYPE]->(m) RETURN n"
|
||||
|
||||
// CREATE and MATCH multiple labels and properties
|
||||
"CREATE (n:LABEL1:LABEL2 {name: \"TEST01\", age: 20}) RETURN n",
|
||||
"MATCH (n:LABEL1:LABEL2 {name: \"TEST01\", age: 20}) RETURN n"
|
||||
// "CREATE (n:LABEL1:LABEL2 {name: \"TEST01\", age: 20}) RETURN n",
|
||||
// "MATCH (n:LABEL1:LABEL2 {name: \"TEST01\", age: 20}) RETURN n"
|
||||
};
|
||||
|
||||
for (auto &query : queries) {
|
||||
|
Loading…
Reference in New Issue
Block a user