Files
memgraph/include/query/stripper.hpp
Marko Budiselic 0fcda94162 Hardcoded query infrastructure - first concrete version - USEFUL FOR: POCs & pilots
Summary: Hardcoded query infrastructure - first concrete version - USEFUL FOR: POCs & pilots

Test Plan: manual + jenkins

Reviewers: sale, florijan

Reviewed By: florijan

Subscribers: pullbot, buda

Differential Revision: https://phabricator.memgraph.io/D45
2017-02-14 09:40:31 +01:00

166 lines
5.9 KiB
C++

#pragma once
#include <vector>
#include <iostream>
#include <string>
#include <tuple>
#include <unordered_map>
#include <utility>
#include "cypher/cypher.h"
#include "logging/loggable.hpp"
#include "query/language/cypher/tokenizer/cypher_lexer.hpp"
#include "storage/model/properties/all.hpp"
#include "utils/hashing/fnv.hpp"
#include "utils/string/transform.hpp"
#include "utils/variadic/variadic.hpp"
#include "query/stripped.hpp"
// TODO: all todos will be resolved once Antler will be integrated
// TODO: Maybe std::move(v) is faster, but it must be cheked for validity.
template <class T, class V>
void store_query_param(PlanArgsT &arguments, V &&v)
{
arguments.emplace_back(Property(T(std::move(v)), T::type));
}
// TODO: hash function should be a template parameter
// TODO: move StrippedQuery into this file, maybe into QueryStripper object
/**
* @class QueryStripper
*
* @brief QueryStripper is responsible for the query stripping
* (taking literal values from the query) and for hash calculation based
* on the stripped query. The whole task is done at once and StrippedQuery
* object is returned as a result.
*
* @tparam Ts type of token ids from underlying lexical analyser. The
* lexical analyser is needed because we have to know what is and
* what isn't a literal value.
*/
template <typename... Ts>
class QueryStripper : public Loggable
{
public:
using HashT = uint64_t;
QueryStripper(Ts &&... strip_types)
: Loggable("QueryStripper"),
strip_types(std::make_tuple(std::forward<Ts>(strip_types)...)),
lexer(std::make_unique<CypherLexer>())
{
}
QueryStripper(QueryStripper &other) = delete;
QueryStripper(QueryStripper &&other)
: Loggable("QueryStripper"), strip_types(std::move(other.strip_types)),
lexer(std::move(other.lexer))
{
}
auto strip(const std::string &query, const std::string &separator = " ")
{
// -------------------------------------------------------------------
// TODO: write speed tests and then optimize, because this
// function is called before every query execution !
// -------------------------------------------------------------------
// TODO write this more optimal (resplace string
// concatenation with something smarter)
// TODO: in place substring replacement
auto tokenizer = lexer->tokenize(query);
// TMP size of supported token types
constexpr auto size = std::tuple_size<decltype(strip_types)>::value;
int counter = 0;
PlanArgsT stripped_arguments;
std::string stripped_query;
stripped_query.reserve(query.size());
while (auto token = tokenizer.lookup())
{
if (_or(token.id, strip_types, std::make_index_sequence<size>{}))
{
auto index = counter++;
switch (token.id)
{
case TK_LONG:
store_query_param<Int64>(stripped_arguments,
std::stol(token.value));
break;
case TK_STR:
// TODO: remove quotes view lexertl
token.value.erase(0, 1);
token.value.erase(token.value.length() - 1, 1);
// TODO: remove
store_query_param<String>(stripped_arguments, token.value);
break;
case TK_BOOL:
{
bool value = token.value[0] == 'T' || token.value[0] == 't';
store_query_param<Bool>(stripped_arguments, value);
break;
}
case TK_FLOAT:
store_query_param<Float>(stripped_arguments,
std::stof(token.value));
break;
default:
// TODO: other properties
assert(false);
}
stripped_query += std::to_string(index) + separator;
}
else
{
// if token is keyword then lowercase because query hash
// should be the same
// TODO: probably we shoud do the lowercase before
// or during the tokenization (SPEED TESTS)
// TODO: stripped shouldn't be responsible for the process
// of lowercasing -> reorganize this in the process of
// Antlr integration
if (token.id == TK_OR || token.id == TK_AND ||
token.id == TK_NOT || token.id == TK_WITH ||
token.id == TK_SET || token.id == TK_CREATE ||
token.id == TK_MERGE || token.id == TK_MATCH ||
token.id == TK_DELETE || token.id == TK_DETACH ||
token.id == TK_WHERE || token.id == TK_RETURN ||
token.id == TK_DISTINCT || token.id == TK_COUNT ||
token.id == TK_LABELS)
{
std::transform(token.value.begin(), token.value.end(),
token.value.begin(), ::tolower);
}
stripped_query += token.value + separator;
}
}
auto hash = fnv(stripped_query);
return StrippedQuery<HashT>(std::move(stripped_query),
std::move(stripped_arguments), hash);
}
private:
std::tuple<Ts...> strip_types;
CypherLexer::uptr lexer;
template <typename Value, typename Tuple, std::size_t... index>
bool _or(Value &&value, Tuple &&tuple, std::index_sequence<index...>)
{
return utils::or_vargs(std::forward<Value>(value),
std::get<index>(std::forward<Tuple>(tuple))...);
}
};
template <typename... Ts>
decltype(auto) make_query_stripper(Ts &&... ts)
{
return QueryStripper<Ts...>(std::forward<Ts>(ts)...);
}