Query stripping now uses a parse tree and differentiates between int literals in a range expression (not stripped) and outside of a range (stripped).
Summary: See above Reviewers: buda, mislav.bradac Reviewed By: mislav.bradac Subscribers: pullbot Differential Revision: https://phabricator.memgraph.io/D98
This commit is contained in:
parent
00d818c762
commit
971e006d13
@ -346,6 +346,7 @@ set(memgraph_src_files
|
||||
${src_dir}/logging/log.cpp
|
||||
${src_dir}/database/graph_db.cpp
|
||||
${src_dir}/database/graph_db_accessor.cpp
|
||||
${src_dir}/query/stripper.cpp
|
||||
${src_dir}/query/backend/cpp/cypher_main_visitor.cpp
|
||||
${src_dir}/query/backend/cpp/typed_value.cpp
|
||||
)
|
||||
|
74
src/query/parameters.hpp
Normal file
74
src/query/parameters.hpp
Normal file
@ -0,0 +1,74 @@
|
||||
//
|
||||
// Copyright 2017 Memgraph
|
||||
// Created by Florijan Stamenkovic on 08.03.17.
|
||||
//
|
||||
|
||||
#ifndef MEMGRAPH_PARAMETERS_HPP
|
||||
#define MEMGRAPH_PARAMETERS_HPP
|
||||
|
||||
#include <query/backend/cpp/typed_value.hpp>
|
||||
|
||||
/**
|
||||
* Encapsulates user provided parameters (and stripped literals)
|
||||
* and provides ways of obtaining them by name or position.
|
||||
*/
|
||||
struct Parameters {
|
||||
public:
|
||||
/**
|
||||
* Adds a value to the stripped arguments under a sequentially
|
||||
* generated name and returns a reference to that name.
|
||||
*
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
const std::string &Add(const TypedValue &value) {
|
||||
return storage_.emplace(NextName(), value).first->first;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value found for the given name.
|
||||
* The name MUST be present in this container
|
||||
* (this is asserted).
|
||||
*
|
||||
* @param name Param name.
|
||||
* @return Value for the given param.
|
||||
*/
|
||||
const TypedValue &At(const std::string &name) const {
|
||||
auto found = storage_.find(name);
|
||||
permanent_assert(found != storage_.end(),
|
||||
"Name must be present in stripped arg container");
|
||||
return found->second;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the position-th stripped value. Asserts that this
|
||||
* container has at least (position + 1) elements.
|
||||
*
|
||||
* This is future proofing for when both query params and
|
||||
* stripping will be supported and naming collisions will have to
|
||||
* be avoided.
|
||||
*
|
||||
* @param position Which stripped param is sought.
|
||||
* @return Stripped param.
|
||||
*/
|
||||
const TypedValue &At(const size_t position) const {
|
||||
permanent_assert(position < storage_.size(), "Invalid position");
|
||||
return storage_.find(NameForPosition(position))->second;
|
||||
}
|
||||
|
||||
/** Returns the number of arguments in this container */
|
||||
const size_t Size() const { return storage_.size(); }
|
||||
|
||||
private:
|
||||
std::map<std::string, TypedValue> storage_;
|
||||
|
||||
/** Generates and returns a new name */
|
||||
std::string NextName() const { return NameForPosition(storage_.size()); }
|
||||
|
||||
/** Returns a name for positon */
|
||||
std::string NameForPosition(unsigned long position) const {
|
||||
return "stripped_arg_" + std::to_string(position);
|
||||
}
|
||||
};
|
||||
|
||||
#endif //MEMGRAPH_PARAMETERS_HPP
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "database/graph_db_accessor.hpp"
|
||||
|
||||
#include "query/stripped.hpp"
|
||||
|
||||
/**
|
||||
@ -18,12 +19,12 @@ class PlanInterface {
|
||||
* concrete execution plan.
|
||||
*
|
||||
* @param db_accessor Accessor for ihe database.
|
||||
* @param args plan argument (vector of literal values from the query)
|
||||
* @param args Plan arguments (including literals stripped from the query).
|
||||
* @param stream stream for results writing
|
||||
*
|
||||
* @return bool status after execution (success OR fail)
|
||||
*/
|
||||
virtual bool run(GraphDbAccessor &db_accessor, const PropertyValueStore<> &args,
|
||||
virtual bool run(GraphDbAccessor &db_accessor, const Parameters &args,
|
||||
Stream &stream) = 0;
|
||||
|
||||
/**
|
||||
|
@ -31,14 +31,10 @@ class QueryPreprocessor : public Loggable {
|
||||
* @return QueryStripped object
|
||||
*/
|
||||
auto preprocess(const std::string &query) {
|
||||
auto preprocessed = stripper.strip(query);
|
||||
|
||||
auto preprocessed = query::Strip(query);
|
||||
logger.info("stripped_query = {}", preprocessed.query);
|
||||
logger.info("query_hash = {}", preprocessed.hash);
|
||||
|
||||
return preprocessed;
|
||||
}
|
||||
|
||||
private:
|
||||
QueryStripper stripper;
|
||||
};
|
||||
|
@ -1,7 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "query/backend/cpp/typed_value.hpp"
|
||||
#include "storage/property_value_store.hpp"
|
||||
|
||||
#include "utils/assert.hpp"
|
||||
#include "utils/hashing/fnv.hpp"
|
||||
#include "parameters.hpp"
|
||||
|
||||
/*
|
||||
* StrippedQuery contains:
|
||||
@ -10,14 +16,13 @@
|
||||
* * hash of stripped query
|
||||
*/
|
||||
struct StrippedQuery {
|
||||
StrippedQuery(const std::string &&query, PropertyValueStore<> &&arguments,
|
||||
StrippedQuery(const std::string &&query,
|
||||
const Parameters &arguments,
|
||||
HashType hash)
|
||||
: query(std::forward<const std::string>(query)),
|
||||
arguments(std::forward<PropertyValueStore<>>(arguments)),
|
||||
hash(hash) {}
|
||||
: query(query), arguments(arguments), hash(hash) {}
|
||||
|
||||
/**
|
||||
* Copy constructor is deleted because we don't want to make unecessary
|
||||
* Copy constructor is deleted because we don't want to make unnecessary
|
||||
* copies of this object (copying of string and vector could be expensive)
|
||||
*/
|
||||
StrippedQuery(const StrippedQuery &other) = delete;
|
||||
@ -38,7 +43,7 @@ struct StrippedQuery {
|
||||
/**
|
||||
* Stripped arguments
|
||||
*/
|
||||
const PropertyValueStore<> arguments;
|
||||
const Parameters arguments;
|
||||
|
||||
/**
|
||||
* Hash based on stripped query.
|
||||
|
221
src/query/stripper.cpp
Normal file
221
src/query/stripper.cpp
Normal file
@ -0,0 +1,221 @@
|
||||
//
|
||||
// Copyright 2017 Memgraph
|
||||
// Created by Florijan Stamenkovic on 07.03.17.
|
||||
//
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "logging/loggable.hpp"
|
||||
#include "query/stripper.hpp"
|
||||
#include "utils/hashing/fnv.hpp"
|
||||
#include "utils/assert.hpp"
|
||||
|
||||
#include "query/frontend/opencypher/generated/CypherBaseVisitor.h"
|
||||
#include "query/frontend/opencypher/generated/CypherLexer.h"
|
||||
#include "query/frontend/opencypher/generated/CypherParser.h"
|
||||
|
||||
using namespace antlr4;
|
||||
using namespace antlropencypher;
|
||||
|
||||
namespace query {
|
||||
|
||||
/**
|
||||
* A visitor that for each literal that is not enclosed
|
||||
* by a range literal calls the given callback (which should
|
||||
* then replace Tokens of literals with placeholders).
|
||||
*/
|
||||
class StripperVisitor : public antlropencypher::CypherBaseVisitor {
|
||||
public:
|
||||
/**
|
||||
* @param callback Callback function (see class description) called
|
||||
* with start and stop tokens of a literal.
|
||||
*/
|
||||
StripperVisitor(const std::function<void(Token *, Token *)> callback)
|
||||
: callback_(callback) {}
|
||||
|
||||
antlrcpp::Any visitRangeLiteral(
|
||||
CypherParser::RangeLiteralContext *ctx) override {
|
||||
is_in_range_ = true;
|
||||
auto r_val = visitChildren(ctx);
|
||||
is_in_range_ = false;
|
||||
return r_val;
|
||||
}
|
||||
|
||||
antlrcpp::Any visitLiteral(
|
||||
CypherParser::LiteralContext *ctx) override {
|
||||
if (ctx->booleanLiteral() != nullptr ||
|
||||
ctx->StringLiteral() != nullptr ||
|
||||
ctx->numberLiteral() != nullptr)
|
||||
callback_(ctx->getStart(), ctx->getStop());
|
||||
|
||||
is_in_literal_ = true;
|
||||
auto r_val = visitChildren(ctx);
|
||||
is_in_literal_ = false;
|
||||
return r_val;
|
||||
}
|
||||
|
||||
antlrcpp::Any visitIntegerLiteral(
|
||||
CypherParser::IntegerLiteralContext *ctx) override {
|
||||
// convert integer literals into param placeholders only if not in range
|
||||
// literal
|
||||
if (!is_in_range_ && !is_in_literal_) callback_(ctx->getStart(), ctx->getStop());
|
||||
return visitChildren(ctx);
|
||||
}
|
||||
|
||||
private:
|
||||
const std::function<void(Token *, Token *)> callback_;
|
||||
bool is_in_range_{false};
|
||||
bool is_in_literal_{false};
|
||||
};
|
||||
|
||||
/**
|
||||
* Strips the input query and returns stripped query, stripped arguments and
|
||||
* stripped query hash.
|
||||
*
|
||||
* @param query input query
|
||||
* @return stripped query, stripped arguments and stripped query hash as a
|
||||
* single object of class StrippedQuery
|
||||
*/
|
||||
StrippedQuery Strip(const std::string &query) {
|
||||
|
||||
// tokenize the query
|
||||
ANTLRInputStream input(query);
|
||||
CypherLexer lexer(&input);
|
||||
CommonTokenStream token_stream(&lexer);
|
||||
token_stream.fill();
|
||||
std::vector<Token *> tokens = token_stream.getTokens();
|
||||
|
||||
// initialize data structures we return
|
||||
Parameters stripped_arguments;
|
||||
|
||||
// convert tokens to strings, perform lowercasing and filtering
|
||||
std::vector<std::string> token_strings;
|
||||
token_strings.reserve(tokens.size());
|
||||
for (int i = 0; i < tokens.size(); ++i)
|
||||
switch (tokens[i]->getType()) {
|
||||
case CypherLexer::UNION:
|
||||
case CypherLexer::ALL:
|
||||
case CypherLexer::OPTIONAL:
|
||||
case CypherLexer::MATCH:
|
||||
case CypherLexer::UNWIND:
|
||||
case CypherLexer::AS:
|
||||
case CypherLexer::MERGE:
|
||||
case CypherLexer::ON:
|
||||
case CypherLexer::CREATE:
|
||||
case CypherLexer::SET:
|
||||
case CypherLexer::DETACH:
|
||||
case CypherLexer::DELETE:
|
||||
case CypherLexer::REMOVE:
|
||||
case CypherLexer::WITH:
|
||||
case CypherLexer::DISTINCT:
|
||||
case CypherLexer::RETURN:
|
||||
case CypherLexer::ORDER:
|
||||
case CypherLexer::BY:
|
||||
case CypherLexer::L_SKIP:
|
||||
case CypherLexer::LIMIT:
|
||||
case CypherLexer::ASCENDING:
|
||||
case CypherLexer::ASC:
|
||||
case CypherLexer::DESCENDING:
|
||||
case CypherLexer::DESC:
|
||||
case CypherLexer::WHERE:
|
||||
case CypherLexer::OR:
|
||||
case CypherLexer::XOR:
|
||||
case CypherLexer::AND:
|
||||
case CypherLexer::NOT:
|
||||
case CypherLexer::IN:
|
||||
case CypherLexer::STARTS:
|
||||
case CypherLexer::ENDS:
|
||||
case CypherLexer::CONTAINS:
|
||||
case CypherLexer::IS:
|
||||
case CypherLexer::CYPHERNULL:
|
||||
case CypherLexer::COUNT:
|
||||
case CypherLexer::FILTER:
|
||||
case CypherLexer::EXTRACT:
|
||||
case CypherLexer::ANY:
|
||||
case CypherLexer::NONE:
|
||||
case CypherLexer::SINGLE:
|
||||
token_strings.push_back(tokens[i]->getText());
|
||||
std::transform(token_strings.back().begin(),
|
||||
token_strings.back().end(),
|
||||
token_strings.back().begin(), ::tolower);
|
||||
break;
|
||||
|
||||
case CypherLexer::SP:
|
||||
case Token::EOF:
|
||||
token_strings.push_back("");
|
||||
break;
|
||||
|
||||
default:
|
||||
token_strings.push_back(tokens[i]->getText());
|
||||
break;
|
||||
}
|
||||
|
||||
// a helper function that generates a new param name for the stripped
|
||||
// literal, appends is to the the stripped_query and adds the passed
|
||||
// value to stripped args
|
||||
auto replace_stripped = [&stripped_arguments, &token_strings](
|
||||
const TypedValue &value, size_t token_position) {
|
||||
const auto &stripped_name = stripped_arguments.Add(value);
|
||||
token_strings[token_position] = "$" + stripped_name;
|
||||
};
|
||||
|
||||
// callback for every literal that should be changed
|
||||
// TODO consider literal parsing problems (like an int with 100 digits)
|
||||
auto callback = [&replace_stripped](Token *start, Token *end) {
|
||||
assert(start->getTokenIndex() == end->getTokenIndex());
|
||||
switch (start->getType()) {
|
||||
case CypherLexer::DecimalInteger:
|
||||
replace_stripped(std::stoi(start->getText()),
|
||||
start->getTokenIndex());
|
||||
break;
|
||||
case CypherLexer::HexInteger:
|
||||
replace_stripped(std::stoi(start->getText(), 0, 16),
|
||||
start->getTokenIndex());
|
||||
break;
|
||||
case CypherLexer::OctalInteger:
|
||||
replace_stripped(std::stoi(start->getText(), 0, 8),
|
||||
start->getTokenIndex());
|
||||
break;
|
||||
case CypherLexer::StringLiteral:
|
||||
replace_stripped(start->getText(),
|
||||
start->getTokenIndex());
|
||||
break;
|
||||
case CypherLexer::RegularDecimalReal:
|
||||
case CypherLexer::ExponentDecimalReal:
|
||||
replace_stripped(std::stof(start->getText()),
|
||||
start->getTokenIndex());
|
||||
break;
|
||||
case CypherLexer::TRUE:
|
||||
replace_stripped(true, start->getTokenIndex());
|
||||
break;
|
||||
case CypherLexer::FALSE:
|
||||
replace_stripped(false, start->getTokenIndex());
|
||||
break;
|
||||
|
||||
default:
|
||||
permanent_assert(true, "Unsupported literal type");
|
||||
}
|
||||
};
|
||||
|
||||
// parse the query and visit the AST with a stripping visitor
|
||||
CypherParser parser(&token_stream);
|
||||
tree::ParseTree *tree = parser.cypher();
|
||||
StripperVisitor stripper_visitor(callback);
|
||||
stripper_visitor.visit(tree);
|
||||
|
||||
// concatenate the stripped query tokens
|
||||
std::string stripped_query;
|
||||
stripped_query.reserve(query.size());
|
||||
for (const std::string &token_string : token_strings) {
|
||||
stripped_query += token_string;
|
||||
if (token_string.size() > 0)
|
||||
stripped_query += " ";
|
||||
}
|
||||
|
||||
// return stripped query, stripped arguments and stripped query hash
|
||||
return StrippedQuery(std::move(stripped_query),
|
||||
std::move(stripped_arguments),
|
||||
fnv(stripped_query));
|
||||
}
|
||||
};
|
@ -1,104 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "logging/loggable.hpp"
|
||||
#include "query/stripped.hpp"
|
||||
#include "storage/property_value_store.hpp"
|
||||
#include "utils/hashing/fnv.hpp"
|
||||
#include "utils/string/transform.hpp"
|
||||
#include "utils/variadic/variadic.hpp"
|
||||
|
||||
#include "antlr4-runtime.h"
|
||||
#include "query/frontend/opencypher/generated/CypherLexer.h"
|
||||
#include "query/frontend/opencypher/generated/CypherParser.h"
|
||||
|
||||
using namespace antlr4;
|
||||
using namespace antlropencypher;
|
||||
|
||||
/**
|
||||
* @brief QueryStripper
|
||||
*
|
||||
* Strips the input query and returns stripped query, stripped arguments and
|
||||
* stripped query hash.
|
||||
*/
|
||||
class QueryStripper : public Loggable {
|
||||
public:
|
||||
QueryStripper() : Loggable("QueryStripper") {}
|
||||
|
||||
QueryStripper(const QueryStripper &) = delete;
|
||||
QueryStripper(QueryStripper &&) = delete;
|
||||
QueryStripper &operator=(const QueryStripper &) = delete;
|
||||
QueryStripper &operator=(QueryStripper &&) = delete;
|
||||
|
||||
/**
|
||||
* Strips the input query (openCypher query).
|
||||
*
|
||||
* @param query input query
|
||||
* @param separator char that is added between all literals in the stripped
|
||||
* query because after stripping compiler frontend will use the stripped
|
||||
* query to AST and literals have to be separated
|
||||
*
|
||||
* @return stripped query, stripped arguments and stripped query hash as a
|
||||
* single object of class StrippedQuery
|
||||
*/
|
||||
auto strip(const std::string &query, const std::string &separator = " ") {
|
||||
// generate tokens
|
||||
ANTLRInputStream input(query);
|
||||
CypherLexer lexer(&input);
|
||||
CommonTokenStream tokens(&lexer);
|
||||
|
||||
// initialize data structures that will be populated
|
||||
PropertyValueStore<> stripped_arguments;
|
||||
std::string stripped_query;
|
||||
stripped_query.reserve(query.size());
|
||||
|
||||
// iterate through tokens -> take arguments and generate stripped query
|
||||
tokens.fill();
|
||||
int counter = 0;
|
||||
for (auto token : tokens.getTokens()) {
|
||||
int type = token->getType();
|
||||
if (type == CypherLexer::DecimalInteger ||
|
||||
type == CypherLexer::StringLiteral ||
|
||||
type == CypherLexer::RegularDecimalReal) { // TODO: add others
|
||||
switch (type) {
|
||||
case CypherLexer::DecimalInteger:
|
||||
stripped_arguments.set(counter, std::stoi(token->getText()));
|
||||
break;
|
||||
case CypherLexer::StringLiteral:
|
||||
stripped_arguments.set(counter, token->getText());
|
||||
break;
|
||||
case CypherLexer::RegularDecimalReal:
|
||||
stripped_arguments.set(counter, std::stof(token->getText()));
|
||||
break;
|
||||
}
|
||||
stripped_query += std::to_string(counter++) + separator;
|
||||
|
||||
} else if (type == CypherLexer::MATCH || type == CypherLexer::CREATE ||
|
||||
type == CypherLexer::RETURN || type == CypherLexer::DELETE ||
|
||||
type == CypherLexer::SET ||
|
||||
type == CypherLexer::WHERE) { // TODO: add others
|
||||
auto value = token->getText();
|
||||
std::transform(value.begin(), value.end(), value.begin(), ::tolower);
|
||||
stripped_query += value + separator;
|
||||
} else if (type == CypherLexer::SP || type < 0 ||
|
||||
type > 113) { // SP || EOF // TODO: add others if exist
|
||||
// pass
|
||||
} else {
|
||||
stripped_query += token->getText() + separator;
|
||||
}
|
||||
}
|
||||
|
||||
// calculate query hash
|
||||
HashType hash = fnv(stripped_query);
|
||||
|
||||
// return stripped query, stripped arguments and stripped query hash
|
||||
return StrippedQuery(std::move(stripped_query),
|
||||
std::move(stripped_arguments), hash);
|
||||
}
|
||||
namespace query {
|
||||
StrippedQuery Strip(const std::string &query);
|
||||
};
|
||||
|
@ -31,8 +31,7 @@ int main(int argc, char **argv) {
|
||||
for (auto &test : tests) {
|
||||
auto *benchmark =
|
||||
benchmark::RegisterBenchmark(test.c_str(), BM_Strip, preprocess, test)
|
||||
->RangeMultiplier(2)
|
||||
->Range(1, 8 << 10)
|
||||
->Range(1, 1)
|
||||
->Complexity(benchmark::oN);
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,7 @@ benchmark_queries:
|
||||
|
||||
- "MATCH (u:User) WITH {key: u} AS nodes DELETE nodes.key"
|
||||
|
||||
- "CREATE ()-[:T {id: 42, alive: true, name: kifla, height=4.2}]->()"
|
||||
- "CREATE ()-[:T {id: 42, alive: true, name: kifla, height: 4.2}]->()"
|
||||
|
||||
- "MATCH p = ()-[r:T]-() WHERE r.id = 42 DELETE r"
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "storage/vertex_accessor.hpp"
|
||||
#include "using.hpp"
|
||||
#include "utils/assert.hpp"
|
||||
#include "query/parameters.hpp"
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
@ -20,7 +21,7 @@ using std::endl;
|
||||
|
||||
class CPUPlan : public PlanInterface<Stream> {
|
||||
public:
|
||||
bool run(GraphDbAccessor &db_accessor, const PropertyValueStore<> &args,
|
||||
bool run(GraphDbAccessor &db_accessor, const Parameters &args,
|
||||
Stream &stream) {
|
||||
return run_general_query(db_accessor, args, stream, CliqueQuery::FIND_ALL);
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "storage/vertex_accessor.hpp"
|
||||
#include "using.hpp"
|
||||
#include "utils/assert.hpp"
|
||||
#include "query/parameters.hpp"
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
@ -116,7 +117,7 @@ class Bitset {
|
||||
enum CliqueQuery { SCORE_AND_LIMIT, FIND_ALL };
|
||||
|
||||
bool run_general_query(GraphDbAccessor &db_accessor,
|
||||
const PropertyValueStore<> &args, Stream &stream,
|
||||
const Parameters &args, Stream &stream,
|
||||
enum CliqueQuery query_type) {
|
||||
if (query_type == CliqueQuery::FIND_ALL)
|
||||
stream.write_fields(
|
||||
@ -129,7 +130,8 @@ bool run_general_query(GraphDbAccessor &db_accessor,
|
||||
// happening in code review!!!
|
||||
auto vertices_iterator = db_accessor.vertices();
|
||||
auto edge_iterator = db_accessor.edges();
|
||||
std::vector<VertexAccessor> vertices(vertices_iterator.begin(), vertices_iterator.end());
|
||||
std::vector<VertexAccessor> vertices(vertices_iterator.begin(),
|
||||
vertices_iterator.end());
|
||||
std::vector<EdgeAccessor> edges(edge_iterator.begin(), edge_iterator.end());
|
||||
|
||||
std::vector<VertexAccessor *> vertices_indexed;
|
||||
@ -142,11 +144,11 @@ bool run_general_query(GraphDbAccessor &db_accessor,
|
||||
if (query_type == CliqueQuery::SCORE_AND_LIMIT &&
|
||||
vertices[i].has_label(db_accessor.label("profile"))) {
|
||||
auto has_prop =
|
||||
vertices[i].PropsAt(db_accessor.property("profile_id")) == args.at(0);
|
||||
vertices[i].PropsAt(db_accessor.property("profile_id")) == args.At(0);
|
||||
if (has_prop.type() == TypedValue::Type::Null) continue;
|
||||
if (has_prop.Value<bool>() == false) continue;
|
||||
has_prop =
|
||||
vertices[i].PropsAt(db_accessor.property("partner_id")) == args.at(1);
|
||||
vertices[i].PropsAt(db_accessor.property("partner_id")) == args.At(1);
|
||||
if (has_prop.type() == TypedValue::Type::Null) continue;
|
||||
if (has_prop.Value<bool>() == false) continue;
|
||||
profile_index = i;
|
||||
@ -184,8 +186,7 @@ bool run_general_query(GraphDbAccessor &db_accessor,
|
||||
* @param bitset bitset to update.
|
||||
* @param edges edges from which to update bitset.
|
||||
*/
|
||||
auto update = [&db_accessor, &query](Bitset<int64_t> &bitset,
|
||||
auto &&edges) {
|
||||
auto update = [&db_accessor, &query](Bitset<int64_t> &bitset, auto &&edges) {
|
||||
for (auto e : edges) {
|
||||
if (e.edge_type() != db_accessor.edge_type("default_outfit")) continue;
|
||||
const int from = query(e.from());
|
||||
@ -208,7 +209,7 @@ bool run_general_query(GraphDbAccessor &db_accessor,
|
||||
for (int i = 0; i < n; ++i) {
|
||||
const VertexAccessor v = *vertices_indexed[i];
|
||||
auto cmp_res = v.PropsAt(db_accessor.property("garment_id")) ==
|
||||
args.at(query_type == CliqueQuery::SCORE_AND_LIMIT ? 8 : 0);
|
||||
args.At(query_type == CliqueQuery::SCORE_AND_LIMIT ? 8 : 0);
|
||||
if (cmp_res.type() != TypedValue::Type::Bool) continue;
|
||||
if (cmp_res.Value<bool>() != true) continue;
|
||||
auto neigh = connected[i].Ones();
|
||||
@ -288,7 +289,7 @@ bool run_general_query(GraphDbAccessor &db_accessor,
|
||||
reverse(results.begin(), results.end());
|
||||
}
|
||||
const int limit = query_type == CliqueQuery::SCORE_AND_LIMIT
|
||||
? args.at((int)args.size() - 1).Value<int>()
|
||||
? args.At((int)args.Size() - 1).Value<int>()
|
||||
: (int)results.size();
|
||||
for (int i = 0; i < std::min(limit, (int)results.size()); ++i) {
|
||||
stream.write_record();
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "storage/vertex_accessor.hpp"
|
||||
#include "using.hpp"
|
||||
#include "utils/assert.hpp"
|
||||
#include "query/parameters.hpp"
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
@ -26,7 +27,7 @@ using std::endl;
|
||||
|
||||
class CPUPlan : public PlanInterface<Stream> {
|
||||
public:
|
||||
bool run(GraphDbAccessor &db_accessor, const PropertyValueStore<> &args,
|
||||
bool run(GraphDbAccessor &db_accessor, const Parameters &args,
|
||||
Stream &stream) {
|
||||
return run_general_query(db_accessor, args, stream,
|
||||
CliqueQuery::SCORE_AND_LIMIT);
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "storage/edge_accessor.hpp"
|
||||
#include "storage/vertex_accessor.hpp"
|
||||
#include "using.hpp"
|
||||
#include "query/parameters.hpp"
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
@ -14,12 +15,12 @@ using std::endl;
|
||||
|
||||
class CPUPlan : public PlanInterface<Stream> {
|
||||
public:
|
||||
bool run(GraphDbAccessor &db_accessor, const PropertyValueStore<> &args,
|
||||
bool run(GraphDbAccessor &db_accessor, const Parameters &args,
|
||||
Stream &stream) {
|
||||
auto v = db_accessor.insert_vertex();
|
||||
v.PropsSet(db_accessor.property("profile_id"), args.at(0));
|
||||
v.PropsSet(db_accessor.property("partner_id"), args.at(1));
|
||||
v.PropsSet(db_accessor.property("conceals"), args.at(2));
|
||||
v.PropsSet(db_accessor.property("profile_id"), args.At(0));
|
||||
v.PropsSet(db_accessor.property("partner_id"), args.At(1));
|
||||
v.PropsSet(db_accessor.property("conceals"), args.At(2));
|
||||
v.add_label(db_accessor.label("profile"));
|
||||
stream.write_field("p");
|
||||
stream.write_vertex_record(v);
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "storage/edge_accessor.hpp"
|
||||
#include "storage/vertex_accessor.hpp"
|
||||
#include "using.hpp"
|
||||
#include "query/parameters.hpp"
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
@ -13,11 +14,11 @@ using std::endl;
|
||||
|
||||
class CPUPlan : public PlanInterface<Stream> {
|
||||
public:
|
||||
bool run(GraphDbAccessor &db_accessor, const PropertyValueStore<> &args,
|
||||
bool run(GraphDbAccessor &db_accessor, const Parameters &args,
|
||||
Stream &stream) {
|
||||
auto v = db_accessor.insert_vertex();
|
||||
v.PropsSet(db_accessor.property("profile_id"), args.at(0));
|
||||
v.PropsSet(db_accessor.property("partner_id"), args.at(1));
|
||||
v.PropsSet(db_accessor.property("profile_id"), args.At(0));
|
||||
v.PropsSet(db_accessor.property("partner_id"), args.At(1));
|
||||
v.add_label(db_accessor.label("profile"));
|
||||
stream.write_field("p");
|
||||
stream.write_vertex_record(v);
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "storage/edge_accessor.hpp"
|
||||
#include "storage/vertex_accessor.hpp"
|
||||
#include "using.hpp"
|
||||
#include "query/parameters.hpp"
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
@ -14,12 +15,12 @@ using std::endl;
|
||||
|
||||
class CPUPlan : public PlanInterface<Stream> {
|
||||
public:
|
||||
bool run(GraphDbAccessor &db_accessor, const PropertyValueStore<> &args,
|
||||
bool run(GraphDbAccessor &db_accessor, const Parameters &args,
|
||||
Stream &stream) {
|
||||
auto v = db_accessor.insert_vertex();
|
||||
v.PropsSet(db_accessor.property("profile_id"), args.at(0));
|
||||
v.PropsSet(db_accessor.property("partner_id"), args.at(1));
|
||||
v.PropsSet(db_accessor.property("reveals"), args.at(2));
|
||||
v.PropsSet(db_accessor.property("profile_id"), args.At(0));
|
||||
v.PropsSet(db_accessor.property("partner_id"), args.At(1));
|
||||
v.PropsSet(db_accessor.property("reveals"), args.At(2));
|
||||
v.add_label(db_accessor.label("profile"));
|
||||
stream.write_field("p");
|
||||
stream.write_vertex_record(v);
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "storage/edge_accessor.hpp"
|
||||
#include "storage/vertex_accessor.hpp"
|
||||
#include "using.hpp"
|
||||
#include "query/parameters.hpp"
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
@ -13,12 +14,12 @@ using std::endl;
|
||||
|
||||
class CPUPlan : public PlanInterface<Stream> {
|
||||
public:
|
||||
bool run(GraphDbAccessor &db_accessor, const PropertyValueStore<> &args,
|
||||
bool run(GraphDbAccessor &db_accessor, const Parameters &args,
|
||||
Stream &stream) {
|
||||
auto v = db_accessor.insert_vertex();
|
||||
v.add_label(db_accessor.label("garment"));
|
||||
v.PropsSet(db_accessor.property("garment_id"), args.at(0));
|
||||
v.PropsSet(db_accessor.property("garment_category_id"), args.at(1));
|
||||
v.PropsSet(db_accessor.property("garment_id"), args.At(0));
|
||||
v.PropsSet(db_accessor.property("garment_category_id"), args.At(1));
|
||||
stream.write_field("g");
|
||||
stream.write_vertex_record(v);
|
||||
stream.write_meta("rw");
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "storage/edge_accessor.hpp"
|
||||
#include "storage/vertex_accessor.hpp"
|
||||
#include "using.hpp"
|
||||
#include "query/parameters.hpp"
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
@ -14,13 +15,13 @@ using std::endl;
|
||||
|
||||
class CPUPlan : public PlanInterface<Stream> {
|
||||
public:
|
||||
bool run(GraphDbAccessor &db_accessor, const PropertyValueStore<> &args,
|
||||
bool run(GraphDbAccessor &db_accessor, const Parameters &args,
|
||||
Stream &stream) {
|
||||
auto v = db_accessor.insert_vertex();
|
||||
v.add_label(db_accessor.label("garment"));
|
||||
v.PropsSet(db_accessor.property("garment_id"), args.at(0));
|
||||
v.PropsSet(db_accessor.property("garment_category_id"), args.at(1));
|
||||
v.PropsSet(db_accessor.property("conceals"), args.at(2));
|
||||
v.PropsSet(db_accessor.property("garment_id"), args.At(0));
|
||||
v.PropsSet(db_accessor.property("garment_category_id"), args.At(1));
|
||||
v.PropsSet(db_accessor.property("conceals"), args.At(2));
|
||||
stream.write_field("g");
|
||||
stream.write_vertex_record(v);
|
||||
stream.write_meta("rw");
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "storage/edge_accessor.hpp"
|
||||
#include "storage/vertex_accessor.hpp"
|
||||
#include "using.hpp"
|
||||
#include "query/parameters.hpp"
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
@ -14,13 +15,13 @@ using std::endl;
|
||||
|
||||
class CPUPlan : public PlanInterface<Stream> {
|
||||
public:
|
||||
bool run(GraphDbAccessor &db_accessor, const PropertyValueStore<> &args,
|
||||
bool run(GraphDbAccessor &db_accessor, const Parameters &args,
|
||||
Stream &stream) {
|
||||
auto v = db_accessor.insert_vertex();
|
||||
v.add_label(db_accessor.label("garment"));
|
||||
v.PropsSet(db_accessor.property("garment_id"), args.at(0));
|
||||
v.PropsSet(db_accessor.property("garment_category_id"), args.at(1));
|
||||
v.PropsSet(db_accessor.property("reveals"), args.at(2));
|
||||
v.PropsSet(db_accessor.property("garment_id"), args.At(0));
|
||||
v.PropsSet(db_accessor.property("garment_category_id"), args.At(1));
|
||||
v.PropsSet(db_accessor.property("reveals"), args.At(2));
|
||||
stream.write_field("g");
|
||||
stream.write_vertex_record(v);
|
||||
stream.write_meta("rw");
|
||||
|
@ -1,8 +1,11 @@
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "query/backend/cpp/typed_value.hpp"
|
||||
#include "query/plan_interface.hpp"
|
||||
#include "query/stripped.hpp"
|
||||
#include "using.hpp"
|
||||
#include "query/parameters.hpp"
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
@ -11,7 +14,7 @@ using std::endl;
|
||||
|
||||
class CPUPlan : public PlanInterface<Stream> {
|
||||
public:
|
||||
bool run(GraphDbAccessor &db_accessor, const PropertyValueStore<> &args,
|
||||
bool run(GraphDbAccessor &db_accessor, const Parameters &args,
|
||||
Stream &stream) {
|
||||
for (auto v : db_accessor.vertices()) db_accessor.detach_remove_vertex(v);
|
||||
stream.write_empty_fields();
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "storage/edge_accessor.hpp"
|
||||
#include "storage/vertex_accessor.hpp"
|
||||
#include "using.hpp"
|
||||
#include "query/parameters.hpp"
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
@ -14,14 +15,14 @@ using std::endl;
|
||||
|
||||
class CPUPlan : public PlanInterface<Stream> {
|
||||
public:
|
||||
bool run(GraphDbAccessor &db_accessor, const PropertyValueStore<> &args,
|
||||
bool run(GraphDbAccessor &db_accessor, const Parameters &args,
|
||||
Stream &stream) {
|
||||
stream.write_field("g");
|
||||
for (auto vertex : db_accessor.vertices()) {
|
||||
if (vertex.has_label(db_accessor.label("garment"))) {
|
||||
TypedValue prop = vertex.PropsAt(db_accessor.property("garment_id"));
|
||||
if (prop.type() == TypedValue::Type::Null) continue;
|
||||
auto cmp = prop == args.at(0);
|
||||
auto cmp = prop == args.At(0);
|
||||
if (cmp.type() != TypedValue::Type::Bool) continue;
|
||||
if (cmp.Value<bool>() != true) continue;
|
||||
stream.write_vertex_record(vertex);
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "storage/edge_accessor.hpp"
|
||||
#include "storage/vertex_accessor.hpp"
|
||||
#include "using.hpp"
|
||||
#include "query/parameters.hpp"
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
@ -15,7 +16,7 @@ using std::endl;
|
||||
|
||||
class CPUPlan : public PlanInterface<Stream> {
|
||||
public:
|
||||
bool run(GraphDbAccessor &db_accessor, const PropertyValueStore<> &args,
|
||||
bool run(GraphDbAccessor &db_accessor, const Parameters &args,
|
||||
Stream &stream) {
|
||||
stream.write_field("r");
|
||||
std::vector<VertexAccessor> g1_set, g2_set;
|
||||
@ -23,7 +24,7 @@ class CPUPlan : public PlanInterface<Stream> {
|
||||
if (g1.has_label(db_accessor.label("garment"))) {
|
||||
TypedValue prop = g1.PropsAt(db_accessor.property("garment_id"));
|
||||
if (prop.type() == TypedValue::Type::Null) continue;
|
||||
auto cmp = prop == args.at(0);
|
||||
auto cmp = prop == args.At(0);
|
||||
if (cmp.type() != TypedValue::Type::Bool) continue;
|
||||
if (cmp.Value<bool>() != true) continue;
|
||||
g1_set.push_back(g1);
|
||||
@ -33,7 +34,7 @@ class CPUPlan : public PlanInterface<Stream> {
|
||||
if (g2.has_label(db_accessor.label("garment"))) {
|
||||
auto prop = g2.PropsAt(db_accessor.property("garment_id"));
|
||||
if (prop.type() == PropertyValue::Type::Null) continue;
|
||||
auto cmp = prop == args.at(1);
|
||||
auto cmp = prop == args.At(1);
|
||||
if (cmp.type() != TypedValue::Type::Bool) continue;
|
||||
if (cmp.Value<bool>() != true) continue;
|
||||
g2_set.push_back(g2);
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "match_garment_set_label_general_return.hpp"
|
||||
#include "query/plan_interface.hpp"
|
||||
#include "using.hpp"
|
||||
#include "query/parameters.hpp"
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
@ -12,7 +13,7 @@ using std::endl;
|
||||
|
||||
class CPUPlan : public PlanInterface<Stream> {
|
||||
public:
|
||||
bool run(GraphDbAccessor &db_accessor, const PropertyValueStore<> &args,
|
||||
bool run(GraphDbAccessor &db_accessor, const Parameters &args,
|
||||
Stream &stream) {
|
||||
return run_general_query(db_accessor, args, stream, "AA");
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "match_garment_set_label_general_return.hpp"
|
||||
#include "query/plan_interface.hpp"
|
||||
#include "using.hpp"
|
||||
#include "query/parameters.hpp"
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
@ -12,7 +13,7 @@ using std::endl;
|
||||
|
||||
class CPUPlan : public PlanInterface<Stream> {
|
||||
public:
|
||||
bool run(GraphDbAccessor &db_accessor, const PropertyValueStore<> &args,
|
||||
bool run(GraphDbAccessor &db_accessor, const Parameters &args,
|
||||
Stream &stream) {
|
||||
return run_general_query(db_accessor, args, stream, "BB");
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "match_garment_set_label_general_return.hpp"
|
||||
#include "query/plan_interface.hpp"
|
||||
#include "using.hpp"
|
||||
#include "query/parameters.hpp"
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
@ -12,7 +13,7 @@ using std::endl;
|
||||
|
||||
class CPUPlan : public PlanInterface<Stream> {
|
||||
public:
|
||||
bool run(GraphDbAccessor &db_accessor, const PropertyValueStore<> &args,
|
||||
bool run(GraphDbAccessor &db_accessor, const Parameters &args,
|
||||
Stream &stream) {
|
||||
return run_general_query(db_accessor, args, stream, "CC");
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "match_garment_set_label_general_return.hpp"
|
||||
#include "query/plan_interface.hpp"
|
||||
#include "using.hpp"
|
||||
#include "query/parameters.hpp"
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
@ -12,7 +13,7 @@ using std::endl;
|
||||
|
||||
class CPUPlan : public PlanInterface<Stream> {
|
||||
public:
|
||||
bool run(GraphDbAccessor &db_accessor, const PropertyValueStore<> &args,
|
||||
bool run(GraphDbAccessor &db_accessor, const Parameters &args,
|
||||
Stream &stream) {
|
||||
return run_general_query(db_accessor, args, stream, "DD");
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "match_garment_set_label_general_return.hpp"
|
||||
#include "query/plan_interface.hpp"
|
||||
#include "using.hpp"
|
||||
#include "query/parameters.hpp"
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
@ -12,7 +13,7 @@ using std::endl;
|
||||
|
||||
class CPUPlan : public PlanInterface<Stream> {
|
||||
public:
|
||||
bool run(GraphDbAccessor &db_accessor, const PropertyValueStore<> &args,
|
||||
bool run(GraphDbAccessor &db_accessor, const Parameters &args,
|
||||
Stream &stream) {
|
||||
return run_general_query(db_accessor, args, stream, "EE");
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include "query/backend/cpp/typed_value.hpp"
|
||||
#include "query/plan_interface.hpp"
|
||||
#include "query/parameters.hpp"
|
||||
#include "storage/edge_accessor.hpp"
|
||||
#include "storage/vertex_accessor.hpp"
|
||||
#include "using.hpp"
|
||||
@ -14,14 +15,14 @@ using std::endl;
|
||||
// RETURN g
|
||||
|
||||
bool run_general_query(GraphDbAccessor &db_accessor,
|
||||
const PropertyValueStore<> &args, Stream &stream,
|
||||
const Parameters &args, Stream &stream,
|
||||
const std::string &general_label) {
|
||||
stream.write_field("g");
|
||||
for (auto vertex : db_accessor.vertices()) {
|
||||
if (vertex.has_label(db_accessor.label("garment"))) {
|
||||
TypedValue prop = vertex.PropsAt(db_accessor.property("garment_id"));
|
||||
if (prop.type() == TypedValue::Type::Null) continue;
|
||||
TypedValue cmp = prop == args.at(0);
|
||||
TypedValue cmp = prop == args.At(0);
|
||||
if (cmp.type() != TypedValue::Type::Bool) continue;
|
||||
if (cmp.Value<bool>() != true) continue;
|
||||
vertex.add_label(db_accessor.label(general_label));
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "storage/edge_accessor.hpp"
|
||||
#include "storage/vertex_accessor.hpp"
|
||||
#include "using.hpp"
|
||||
#include "query/parameters.hpp"
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
@ -14,20 +15,20 @@ using std::endl;
|
||||
|
||||
class CPUPlan : public PlanInterface<Stream> {
|
||||
public:
|
||||
bool run(GraphDbAccessor &db_accessor, const PropertyValueStore<> &args,
|
||||
bool run(GraphDbAccessor &db_accessor, const Parameters &args,
|
||||
Stream &stream) {
|
||||
stream.write_field("p");
|
||||
for (auto vertex : db_accessor.vertices()) {
|
||||
if (vertex.has_label(db_accessor.label("profile"))) {
|
||||
TypedValue prop = vertex.PropsAt(db_accessor.property("profile_id"));
|
||||
if (prop.type() == TypedValue::Type::Null) continue;
|
||||
auto cmp = prop == args.at(0);
|
||||
auto cmp = prop == args.At(0);
|
||||
if (cmp.type() != TypedValue::Type::Bool) continue;
|
||||
if (cmp.Value<bool>() != true) continue;
|
||||
|
||||
TypedValue prop2 = vertex.PropsAt(db_accessor.property("partner_id"));
|
||||
if (prop2.type() == TypedValue::Type::Null) continue;
|
||||
auto cmp2 = prop2 == args.at(1);
|
||||
auto cmp2 = prop2 == args.At(1);
|
||||
if (cmp2.type() != TypedValue::Type::Bool) continue;
|
||||
if (cmp2.Value<bool>() != true) continue;
|
||||
stream.write_vertex_record(vertex);
|
||||
|
@ -3,9 +3,11 @@
|
||||
|
||||
#include "query/backend/cpp/typed_value.hpp"
|
||||
#include "query/plan_interface.hpp"
|
||||
#include "query/stripped.hpp"
|
||||
#include "storage/edge_accessor.hpp"
|
||||
#include "storage/vertex_accessor.hpp"
|
||||
#include "using.hpp"
|
||||
#include "query/parameters.hpp"
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
@ -16,26 +18,26 @@ using std::endl;
|
||||
|
||||
class CPUPlan : public PlanInterface<Stream> {
|
||||
public:
|
||||
bool run(GraphDbAccessor &db_accessor, const PropertyValueStore<> &args,
|
||||
bool run(GraphDbAccessor &db_accessor, const Parameters &args,
|
||||
Stream &stream) {
|
||||
stream.write_field("s");
|
||||
auto profile = [&db_accessor, &args](const VertexAccessor &v) -> bool {
|
||||
TypedValue prop = v.PropsAt(db_accessor.property("profile_id"));
|
||||
if (prop.type() == TypedValue::Type::Null) return false;
|
||||
auto cmp = prop == args.at(0);
|
||||
auto cmp = prop == args.At(0);
|
||||
if (cmp.type() != TypedValue::Type::Bool) return false;
|
||||
if (cmp.Value<bool>() != true) return false;
|
||||
|
||||
TypedValue prop2 = v.PropsAt(db_accessor.property("partner_id"));
|
||||
if (prop2.type() == TypedValue::Type::Null) return false;
|
||||
auto cmp2 = prop2 == args.at(1);
|
||||
auto cmp2 = prop2 == args.At(1);
|
||||
if (cmp2.type() != TypedValue::Type::Bool) return false;
|
||||
return cmp2.Value<bool>();
|
||||
};
|
||||
auto garment = [&db_accessor, &args](const VertexAccessor &v) -> bool {
|
||||
TypedValue prop = v.PropsAt(db_accessor.property("garment_id"));
|
||||
if (prop.type() == TypedValue::Type::Null) return false;
|
||||
auto cmp = prop == args.at(2);
|
||||
auto cmp = prop == args.At(2);
|
||||
if (cmp.type() != TypedValue::Type::Bool) return false;
|
||||
return cmp.Value<bool>();
|
||||
};
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "storage/edge_accessor.hpp"
|
||||
#include "storage/vertex_accessor.hpp"
|
||||
#include "using.hpp"
|
||||
#include "query/parameters.hpp"
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
@ -15,7 +16,7 @@ using std::endl;
|
||||
|
||||
class CPUPlan : public PlanInterface<Stream> {
|
||||
public:
|
||||
bool run(GraphDbAccessor &db_accessor, const PropertyValueStore<> &args,
|
||||
bool run(GraphDbAccessor &db_accessor, const Parameters &args,
|
||||
Stream &stream) {
|
||||
stream.write_field("r");
|
||||
std::vector<VertexAccessor> g1_set, g2_set;
|
||||
@ -23,13 +24,13 @@ class CPUPlan : public PlanInterface<Stream> {
|
||||
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;
|
||||
auto cmp = prop == args.at(0);
|
||||
auto cmp = prop == args.At(0);
|
||||
if (cmp.type() != TypedValue::Type::Bool) continue;
|
||||
if (cmp.Value<bool>() != true) continue;
|
||||
|
||||
auto prop2 = TypedValue(g1.PropsAt(db_accessor.property("partner_id")));
|
||||
if (prop2.type() == TypedValue::Type::Null) continue;
|
||||
auto cmp2 = prop2 == args.at(1);
|
||||
auto cmp2 = prop2 == args.At(1);
|
||||
if (cmp2.type() != TypedValue::Type::Bool) continue;
|
||||
if (cmp2.Value<bool>() != true) continue;
|
||||
g1_set.push_back(g1);
|
||||
@ -39,7 +40,7 @@ class CPUPlan : public PlanInterface<Stream> {
|
||||
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;
|
||||
auto cmp = prop == args.at(2);
|
||||
auto cmp = prop == args.At(2);
|
||||
if (cmp.type() != TypedValue::Type::Bool) continue;
|
||||
if (cmp.Value<bool>() != true) continue;
|
||||
g2_set.push_back(g2);
|
||||
@ -49,7 +50,7 @@ class CPUPlan : public PlanInterface<Stream> {
|
||||
for (auto g2 : g2_set) {
|
||||
EdgeAccessor e =
|
||||
db_accessor.insert_edge(g1, g2, db_accessor.edge_type("score"));
|
||||
e.PropsSet(db_accessor.property("score"), args.at(3));
|
||||
e.PropsSet(db_accessor.property("score"), args.At(3));
|
||||
stream.write_edge_record(e);
|
||||
}
|
||||
stream.write_meta("rw");
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "storage/edge_accessor.hpp"
|
||||
#include "storage/vertex_accessor.hpp"
|
||||
#include "using.hpp"
|
||||
#include "query/parameters.hpp"
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
@ -16,26 +17,26 @@ using std::endl;
|
||||
|
||||
class CPUPlan : public PlanInterface<Stream> {
|
||||
public:
|
||||
bool run(GraphDbAccessor &db_accessor, const PropertyValueStore<> &args,
|
||||
bool run(GraphDbAccessor &db_accessor, const Parameters &args,
|
||||
Stream &stream) {
|
||||
stream.write_field("s");
|
||||
auto profile = [&db_accessor, &args](const VertexAccessor &v) -> bool {
|
||||
TypedValue prop = v.PropsAt(db_accessor.property("profile_id"));
|
||||
if (prop.type() == TypedValue::Type::Null) return false;
|
||||
auto cmp = prop == args.at(0);
|
||||
auto cmp = prop == args.At(0);
|
||||
if (cmp.type() != TypedValue::Type::Bool) return false;
|
||||
if (cmp.Value<bool>() != true) return false;
|
||||
|
||||
TypedValue prop2 = v.PropsAt(db_accessor.property("partner_id"));
|
||||
if (prop2.type() == TypedValue::Type::Null) return false;
|
||||
auto cmp2 = prop2 == args.at(1);
|
||||
auto cmp2 = prop2 == args.At(1);
|
||||
if (cmp2.type() != TypedValue::Type::Bool) return false;
|
||||
return cmp2.Value<bool>();
|
||||
};
|
||||
auto garment = [&db_accessor, &args](const VertexAccessor &v) -> bool {
|
||||
TypedValue prop = v.PropsAt(db_accessor.property("garment_id"));
|
||||
if (prop.type() == TypedValue::Type::Null) return false;
|
||||
auto cmp = prop == args.at(2);
|
||||
auto cmp = prop == args.At(2);
|
||||
if (cmp.type() != TypedValue::Type::Bool) return false;
|
||||
return cmp.Value<bool>();
|
||||
};
|
||||
@ -44,7 +45,7 @@ class CPUPlan : public PlanInterface<Stream> {
|
||||
auto to = edge.to();
|
||||
if (edge.edge_type() != db_accessor.edge_type("score")) continue;
|
||||
if ((profile(from) && garment(to)) || (profile(to) && garment(from))) {
|
||||
edge.PropsSet(db_accessor.property("score"), args.at(3));
|
||||
edge.PropsSet(db_accessor.property("score"), args.At(3));
|
||||
stream.write_edge_record(edge);
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ using std::endl;
|
||||
|
||||
class CPUPlan : public PlanInterface<Stream> {
|
||||
public:
|
||||
bool run(GraphDbAccessor &db_accessor, const PropertyValueStore<> &args,
|
||||
bool run(GraphDbAccessor &db_accessor, const StrippedArguments &args,
|
||||
Stream &stream) {
|
||||
db_accessor.commit();
|
||||
return true;
|
||||
|
@ -36,9 +36,8 @@ int main(int argc, char **argv) {
|
||||
println("Stripped query: ", preprocessed.query);
|
||||
println("Query hash: ", preprocessed.hash);
|
||||
println("Property values:");
|
||||
for (auto property : preprocessed.arguments) {
|
||||
println(" ", property.second);
|
||||
}
|
||||
for (int i = 0; i < preprocessed.arguments.Size(); ++i)
|
||||
println(" ", preprocessed.arguments.At(i));
|
||||
println("");
|
||||
|
||||
return 0;
|
||||
|
28
tests/manual/query_stripper_timing.cpp
Normal file
28
tests/manual/query_stripper_timing.cpp
Normal file
@ -0,0 +1,28 @@
|
||||
//
|
||||
// Copyright 2017 Memgraph
|
||||
// Created by Florijan Stamenkovic on 07.03.17.
|
||||
//
|
||||
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
|
||||
#include "query/stripper.hpp"
|
||||
|
||||
int main(int argc, const char **a) {
|
||||
if (argc < 2) {
|
||||
std::cout << "Provide a query string as input" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char *query = a[1];
|
||||
const int REPEATS = 100;
|
||||
|
||||
clock_t begin = clock();
|
||||
for (int i = 0; i < REPEATS; ++i)
|
||||
query::Strip(query);
|
||||
clock_t end = clock();
|
||||
|
||||
double elapsed_secs = double(end - begin) / CLOCKS_PER_SEC;
|
||||
std::cout << "Performed " << REPEATS << " strip ops, each took "
|
||||
<< elapsed_secs / REPEATS * 1000 << "ms" << std::endl;
|
||||
}
|
90
tests/unit/query_stripper.cpp
Normal file
90
tests/unit/query_stripper.cpp
Normal file
@ -0,0 +1,90 @@
|
||||
//
|
||||
// Copyright 2017 Memgraph
|
||||
// Created by Florijan Stamenkovic on 07.03.17.
|
||||
//
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "query/stripper.hpp"
|
||||
|
||||
void EXPECT_PROP_TRUE(const TypedValue& a) {
|
||||
EXPECT_TRUE(a.type() == TypedValue::Type::Bool && a.Value<bool>());
|
||||
}
|
||||
|
||||
void EXPECT_PROP_EQ(const TypedValue& a, const TypedValue& b) {
|
||||
EXPECT_PROP_TRUE(a == b);
|
||||
}
|
||||
|
||||
TEST(QueryStripper, NoLiterals) {
|
||||
StrippedQuery stripped = query::Strip("CREATE (n)");
|
||||
EXPECT_EQ(stripped.arguments.Size(), 0);
|
||||
EXPECT_EQ(stripped.query, "create ( n ) ");
|
||||
}
|
||||
|
||||
TEST(QueryStripper, DecimalInteger) {
|
||||
StrippedQuery stripped = query::Strip("RETURN 42");
|
||||
EXPECT_EQ(stripped.arguments.Size(), 1);
|
||||
EXPECT_EQ(stripped.arguments.At(0).Value<int>(), 42);
|
||||
EXPECT_EQ(stripped.query, "return $stripped_arg_0 ");
|
||||
}
|
||||
|
||||
TEST(QueryStripper, OctalInteger) {
|
||||
StrippedQuery stripped = query::Strip("RETURN 010");
|
||||
EXPECT_EQ(stripped.arguments.Size(), 1);
|
||||
EXPECT_EQ(stripped.arguments.At(0).Value<int>(), 8);
|
||||
EXPECT_EQ(stripped.query, "return $stripped_arg_0 ");
|
||||
}
|
||||
|
||||
TEST(QueryStripper, HexInteger) {
|
||||
StrippedQuery stripped = query::Strip("RETURN 0xa");
|
||||
EXPECT_EQ(stripped.arguments.Size(), 1);
|
||||
EXPECT_EQ(stripped.arguments.At(0).Value<int>(), 10);
|
||||
EXPECT_EQ(stripped.query, "return $stripped_arg_0 ");
|
||||
}
|
||||
|
||||
TEST(QueryStripper, RegularDecimal) {
|
||||
StrippedQuery stripped = query::Strip("RETURN 42.3");
|
||||
EXPECT_EQ(stripped.arguments.Size(), 1);
|
||||
EXPECT_FLOAT_EQ(stripped.arguments.At(0).Value<double>(), 42.3);
|
||||
EXPECT_EQ(stripped.query, "return $stripped_arg_0 ");
|
||||
}
|
||||
|
||||
TEST(QueryStripper, ExponentDecimal) {
|
||||
StrippedQuery stripped = query::Strip("RETURN 4e2");
|
||||
EXPECT_EQ(stripped.arguments.Size(), 1);
|
||||
EXPECT_FLOAT_EQ(stripped.arguments.At(0).Value<double>(), 4e2);
|
||||
EXPECT_EQ(stripped.query, "return $stripped_arg_0 ");
|
||||
}
|
||||
|
||||
TEST(QueryStripper, StringLiteral) {
|
||||
StrippedQuery stripped = query::Strip("RETURN 'something'");
|
||||
EXPECT_EQ(stripped.arguments.Size(), 1);
|
||||
EXPECT_EQ(stripped.arguments.At(0).Value<std::string>(), "'something'");
|
||||
EXPECT_EQ(stripped.query, "return $stripped_arg_0 ");
|
||||
}
|
||||
|
||||
TEST(QueryStripper, BoolLiteral) {
|
||||
StrippedQuery stripped = query::Strip("RETURN true");
|
||||
EXPECT_EQ(stripped.arguments.Size(), 1);
|
||||
EXPECT_PROP_EQ(stripped.arguments.At(0), TypedValue(true));
|
||||
EXPECT_EQ(stripped.query, "return $stripped_arg_0 ");
|
||||
}
|
||||
|
||||
TEST(QueryStripper, ListLiteral) {
|
||||
StrippedQuery stripped = query::Strip("MATCH (n) RETURN [n, n.prop]");
|
||||
EXPECT_EQ(stripped.arguments.Size(), 0);
|
||||
EXPECT_EQ(stripped.query, "match ( n ) return [ n , n . prop ] ");
|
||||
}
|
||||
|
||||
TEST(QueryStripper, MapLiteral) {
|
||||
StrippedQuery stripped = query::Strip("MATCH (n) RETURN {val: n}");
|
||||
EXPECT_EQ(stripped.arguments.Size(), 0);
|
||||
EXPECT_EQ(stripped.query, "match ( n ) return { val : n } ");
|
||||
}
|
||||
|
||||
TEST(QueryStripper, RangeLiteral) {
|
||||
StrippedQuery stripped = query::Strip("MATCH (n)-[*2..3]-() RETURN n");
|
||||
EXPECT_EQ(stripped.arguments.Size(), 0);
|
||||
EXPECT_EQ(stripped.query, "match ( n ) - [ * 2 .. 3 ] - ( ) return n ");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user