2017-04-24 19:51:16 +08:00
|
|
|
/// @file
|
|
|
|
/// This file provides macros for easier construction of openCypher query AST.
|
|
|
|
/// The usage of macros is very similar to how one would write openCypher. For
|
|
|
|
/// example:
|
|
|
|
///
|
2018-05-22 22:45:52 +08:00
|
|
|
/// AstStorage storage; // Macros rely on storage being in scope.
|
2018-06-19 19:52:11 +08:00
|
|
|
/// // PROPERTY_LOOKUP and PROPERTY_PAIR macros
|
2018-07-26 15:08:21 +08:00
|
|
|
/// // rely on a DbAccessor *reference* named dba.
|
2018-10-09 17:09:10 +08:00
|
|
|
/// database::GraphDb db;
|
2018-07-26 15:08:21 +08:00
|
|
|
/// auto dba_ptr = db.Access();
|
|
|
|
/// auto &dba = *dba_ptr;
|
2017-04-24 19:51:16 +08:00
|
|
|
///
|
|
|
|
/// QUERY(MATCH(PATTERN(NODE("n"), EDGE("e"), NODE("m"))),
|
|
|
|
/// WHERE(LESS(PROPERTY_LOOKUP("e", edge_prop), LITERAL(3))),
|
|
|
|
/// RETURN(SUM(PROPERTY_LOOKUP("m", prop)), AS("sum"),
|
|
|
|
/// ORDER_BY(IDENT("sum")),
|
|
|
|
/// SKIP(ADD(LITERAL(1), LITERAL(2)))));
|
|
|
|
///
|
|
|
|
/// Each of the macros is accompanied by a function. The functions use overload
|
|
|
|
/// resolution and template magic to provide a type safe way of constructing
|
|
|
|
/// queries. Although the functions can be used by themselves, it is more
|
|
|
|
/// convenient to use the macros.
|
|
|
|
|
2017-05-30 21:19:38 +08:00
|
|
|
#pragma once
|
|
|
|
|
2017-09-18 20:40:36 +08:00
|
|
|
#include <map>
|
|
|
|
#include <string>
|
2017-10-02 16:34:38 +08:00
|
|
|
#include <unordered_map>
|
2017-04-24 19:51:16 +08:00
|
|
|
#include <utility>
|
|
|
|
#include <vector>
|
|
|
|
|
2017-04-24 22:01:00 +08:00
|
|
|
#include "query/frontend/ast/ast.hpp"
|
2018-10-04 21:23:07 +08:00
|
|
|
#include "storage/common/types.hpp"
|
2017-06-05 17:50:47 +08:00
|
|
|
#include "utils/string.hpp"
|
2017-03-29 18:37:58 +08:00
|
|
|
|
2017-03-24 23:50:42 +08:00
|
|
|
namespace query {
|
|
|
|
|
|
|
|
namespace test_common {
|
|
|
|
|
2017-08-21 21:44:35 +08:00
|
|
|
template <typename T>
|
|
|
|
auto ToList(const TypedValue &t) {
|
|
|
|
std::vector<T> list;
|
2017-05-19 21:49:25 +08:00
|
|
|
for (auto x : t.Value<std::vector<TypedValue>>()) {
|
2017-08-21 21:44:35 +08:00
|
|
|
list.push_back(x.Value<T>());
|
2017-05-19 21:49:25 +08:00
|
|
|
}
|
|
|
|
return list;
|
|
|
|
};
|
|
|
|
|
Collect Map added
Summary:
Tests are on the way. Please first comment if you're OK with this implementation, some points are discussable.
What works now:
```
bash:MEMGRAPH_ROOT/build/>./tests/manual/console 10
MG>MATCH (n) RETURN COLLECT("age_" + n.age, n.height)
+-----------------------------------------------------------------------------------------------------------------------------------+
| COLLECT("age_" + n.age, n.height) |
+-----------------------------------------------------------------------------------------------------------------------------------+
| {age_10: 176, age_13: 180, age_24: 172, age_25: 179, age_32: 123, age_33: 186, age_37: 147, age_43: 162, age_49: 126, age_6: 170} |
+-----------------------------------------------------------------------------------------------------------------------------------+
```
Reviewers: mislav.bradac, teon.banek, buda
Reviewed By: mislav.bradac, buda
Subscribers: pullbot
Differential Revision: https://phabricator.memgraph.io/D695
2017-08-23 16:43:45 +08:00
|
|
|
template <typename TElement>
|
|
|
|
auto ToMap(const TypedValue &t) {
|
|
|
|
std::map<std::string, TElement> map;
|
|
|
|
for (const auto &kv : t.Value<std::map<std::string, TypedValue>>())
|
|
|
|
map.emplace(kv.first, kv.second.Value<TElement>());
|
|
|
|
return map;
|
|
|
|
};
|
|
|
|
|
2017-04-26 19:49:41 +08:00
|
|
|
// Custom types for ORDER BY, SKIP, LIMIT, ON MATCH and ON CREATE expressions,
|
|
|
|
// so that they can be used to resolve function calls.
|
2017-04-24 19:51:16 +08:00
|
|
|
struct OrderBy {
|
2018-10-04 17:57:23 +08:00
|
|
|
std::vector<SortItem> expressions;
|
2017-04-24 19:51:16 +08:00
|
|
|
};
|
2017-04-20 17:20:20 +08:00
|
|
|
struct Skip {
|
2017-04-24 19:51:16 +08:00
|
|
|
Expression *expression = nullptr;
|
2017-04-20 17:20:20 +08:00
|
|
|
};
|
|
|
|
struct Limit {
|
2017-04-24 19:51:16 +08:00
|
|
|
Expression *expression = nullptr;
|
2017-04-20 17:20:20 +08:00
|
|
|
};
|
2017-04-26 19:49:41 +08:00
|
|
|
struct OnMatch {
|
|
|
|
std::vector<Clause *> set;
|
|
|
|
};
|
|
|
|
struct OnCreate {
|
|
|
|
std::vector<Clause *> set;
|
|
|
|
};
|
2017-04-20 17:20:20 +08:00
|
|
|
|
2017-04-24 19:51:16 +08:00
|
|
|
// Helper functions for filling the OrderBy with expressions.
|
|
|
|
auto FillOrderBy(OrderBy &order_by, Expression *expression,
|
|
|
|
Ordering ordering = Ordering::ASC) {
|
2018-10-04 17:57:23 +08:00
|
|
|
order_by.expressions.push_back({ordering, expression});
|
2017-04-24 19:51:16 +08:00
|
|
|
}
|
|
|
|
template <class... T>
|
|
|
|
auto FillOrderBy(OrderBy &order_by, Expression *expression, Ordering ordering,
|
|
|
|
T... rest) {
|
|
|
|
FillOrderBy(order_by, expression, ordering);
|
|
|
|
FillOrderBy(order_by, rest...);
|
|
|
|
}
|
|
|
|
template <class... T>
|
|
|
|
auto FillOrderBy(OrderBy &order_by, Expression *expression, T... rest) {
|
|
|
|
FillOrderBy(order_by, expression);
|
|
|
|
FillOrderBy(order_by, rest...);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Create OrderBy expressions.
|
|
|
|
///
|
|
|
|
/// The supported combination of arguments is: (Expression, [Ordering])+
|
|
|
|
/// Since the Ordering is optional, by default it is ascending.
|
|
|
|
template <class... T>
|
|
|
|
auto GetOrderBy(T... exprs) {
|
|
|
|
OrderBy order_by;
|
|
|
|
FillOrderBy(order_by, exprs...);
|
|
|
|
return order_by;
|
|
|
|
}
|
|
|
|
|
2017-03-24 23:50:42 +08:00
|
|
|
/// Create PropertyLookup with given name and property.
|
|
|
|
///
|
|
|
|
/// Name is used to create the Identifier which is used for property lookup.
|
2018-06-19 19:52:11 +08:00
|
|
|
template <class TDbAccessor>
|
|
|
|
auto GetPropertyLookup(AstStorage &storage, TDbAccessor &dba,
|
2018-01-16 17:09:15 +08:00
|
|
|
const std::string &name, storage::Property property) {
|
2017-03-24 23:50:42 +08:00
|
|
|
return storage.Create<PropertyLookup>(storage.Create<Identifier>(name),
|
2017-10-30 17:43:25 +08:00
|
|
|
dba.PropertyName(property), property);
|
2017-03-24 23:50:42 +08:00
|
|
|
}
|
2018-06-19 19:52:11 +08:00
|
|
|
|
|
|
|
template <class TDbAccessor>
|
|
|
|
auto GetPropertyLookup(AstStorage &storage, TDbAccessor &dba, Expression *expr,
|
|
|
|
storage::Property property) {
|
2017-10-30 17:43:25 +08:00
|
|
|
return storage.Create<PropertyLookup>(expr, dba.PropertyName(property),
|
2017-08-08 19:43:42 +08:00
|
|
|
property);
|
|
|
|
}
|
2018-06-19 19:52:11 +08:00
|
|
|
|
|
|
|
template <class TDbAccessor>
|
2017-08-08 19:43:42 +08:00
|
|
|
auto GetPropertyLookup(
|
2018-06-19 19:52:11 +08:00
|
|
|
AstStorage &storage, TDbAccessor &, const std::string &name,
|
2018-01-16 17:09:15 +08:00
|
|
|
const std::pair<std::string, storage::Property> &prop_pair) {
|
2017-08-08 19:43:42 +08:00
|
|
|
return storage.Create<PropertyLookup>(storage.Create<Identifier>(name),
|
|
|
|
prop_pair.first, prop_pair.second);
|
|
|
|
}
|
2018-06-19 19:52:11 +08:00
|
|
|
|
|
|
|
template <class TDbAccessor>
|
2017-08-08 19:43:42 +08:00
|
|
|
auto GetPropertyLookup(
|
2018-06-19 19:52:11 +08:00
|
|
|
AstStorage &storage, TDbAccessor &, Expression *expr,
|
2018-01-16 17:09:15 +08:00
|
|
|
const std::pair<std::string, storage::Property> &prop_pair) {
|
2017-08-08 19:43:42 +08:00
|
|
|
return storage.Create<PropertyLookup>(expr, prop_pair.first,
|
|
|
|
prop_pair.second);
|
2017-05-05 21:34:07 +08:00
|
|
|
}
|
2017-03-24 23:50:42 +08:00
|
|
|
|
2017-10-05 17:25:52 +08:00
|
|
|
/// Create an EdgeAtom with given name, direction and edge_type.
|
2017-03-24 23:50:42 +08:00
|
|
|
///
|
|
|
|
/// Name is used to create the Identifier which is assigned to the edge.
|
2018-05-22 22:45:52 +08:00
|
|
|
auto GetEdge(AstStorage &storage, const std::string &name,
|
2017-10-05 17:25:52 +08:00
|
|
|
EdgeAtom::Direction dir = EdgeAtom::Direction::BOTH,
|
2018-01-16 17:09:15 +08:00
|
|
|
const std::vector<storage::EdgeType> &edge_types = {}) {
|
2017-10-05 17:25:52 +08:00
|
|
|
return storage.Create<EdgeAtom>(storage.Create<Identifier>(name),
|
|
|
|
EdgeAtom::Type::SINGLE, dir, edge_types);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Create a variable length expansion EdgeAtom with given name, direction and
|
|
|
|
/// edge_type.
|
2017-03-24 23:50:42 +08:00
|
|
|
///
|
2017-10-05 17:25:52 +08:00
|
|
|
/// Name is used to create the Identifier which is assigned to the edge.
|
2018-05-22 22:45:52 +08:00
|
|
|
auto GetEdgeVariable(AstStorage &storage, const std::string &name,
|
2017-10-05 17:25:52 +08:00
|
|
|
EdgeAtom::Direction dir = EdgeAtom::Direction::BOTH,
|
2018-01-16 17:09:15 +08:00
|
|
|
const std::vector<storage::EdgeType> &edge_types = {},
|
2017-10-05 17:25:52 +08:00
|
|
|
Identifier *inner_edge = nullptr,
|
|
|
|
Identifier *inner_node = nullptr) {
|
|
|
|
auto r_val =
|
|
|
|
storage.Create<EdgeAtom>(storage.Create<Identifier>(name),
|
|
|
|
EdgeAtom::Type::DEPTH_FIRST, dir, edge_types);
|
2018-02-08 19:57:12 +08:00
|
|
|
r_val->filter_lambda_.inner_edge =
|
2018-01-12 22:17:04 +08:00
|
|
|
inner_edge ? inner_edge
|
|
|
|
: storage.Create<Identifier>(utils::RandomString(20));
|
2018-02-08 19:57:12 +08:00
|
|
|
r_val->filter_lambda_.inner_node =
|
2018-01-12 22:17:04 +08:00
|
|
|
inner_node ? inner_node
|
|
|
|
: storage.Create<Identifier>(utils::RandomString(20));
|
2017-10-05 17:25:52 +08:00
|
|
|
return r_val;
|
2017-03-24 23:50:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Create a NodeAtom with given name and label.
|
|
|
|
///
|
|
|
|
/// Name is used to create the Identifier which is assigned to the node.
|
2018-05-22 22:45:52 +08:00
|
|
|
auto GetNode(AstStorage &storage, const std::string &name,
|
2018-01-16 17:09:15 +08:00
|
|
|
std::experimental::optional<storage::Label> label =
|
2017-11-23 23:36:54 +08:00
|
|
|
std::experimental::nullopt) {
|
2017-03-24 23:50:42 +08:00
|
|
|
auto node = storage.Create<NodeAtom>(storage.Create<Identifier>(name));
|
2017-11-23 23:36:54 +08:00
|
|
|
if (label) node->labels_.emplace_back(*label);
|
2017-03-24 23:50:42 +08:00
|
|
|
return node;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Create a Pattern with given atoms.
|
2018-05-22 22:45:52 +08:00
|
|
|
auto GetPattern(AstStorage &storage, std::vector<PatternAtom *> atoms) {
|
2017-03-24 23:50:42 +08:00
|
|
|
auto pattern = storage.Create<Pattern>();
|
2017-12-01 17:42:53 +08:00
|
|
|
pattern->identifier_ =
|
|
|
|
storage.Create<Identifier>(utils::RandomString(20), false);
|
2017-09-18 20:40:36 +08:00
|
|
|
pattern->atoms_.insert(pattern->atoms_.begin(), atoms.begin(), atoms.end());
|
|
|
|
return pattern;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Create a Pattern with given name and atoms.
|
2018-05-22 22:45:52 +08:00
|
|
|
auto GetPattern(AstStorage &storage, const std::string &name,
|
2017-09-18 20:40:36 +08:00
|
|
|
std::vector<PatternAtom *> atoms) {
|
|
|
|
auto pattern = storage.Create<Pattern>();
|
|
|
|
pattern->identifier_ = storage.Create<Identifier>(name, true);
|
2017-03-24 23:50:42 +08:00
|
|
|
pattern->atoms_.insert(pattern->atoms_.begin(), atoms.begin(), atoms.end());
|
|
|
|
return pattern;
|
|
|
|
}
|
|
|
|
|
2017-04-28 16:37:49 +08:00
|
|
|
/// This function fills an AST node which with given patterns.
|
2017-03-24 23:50:42 +08:00
|
|
|
///
|
|
|
|
/// The function is most commonly used to create Match and Create clauses.
|
|
|
|
template <class TWithPatterns>
|
2017-04-28 16:37:49 +08:00
|
|
|
auto GetWithPatterns(TWithPatterns *with_patterns,
|
|
|
|
std::vector<Pattern *> patterns) {
|
2017-03-24 23:50:42 +08:00
|
|
|
with_patterns->patterns_.insert(with_patterns->patterns_.begin(),
|
|
|
|
patterns.begin(), patterns.end());
|
|
|
|
return with_patterns;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Create a query with given clauses.
|
2017-11-29 20:55:02 +08:00
|
|
|
|
|
|
|
auto GetSingleQuery(SingleQuery *single_query, Clause *clause) {
|
|
|
|
single_query->clauses_.emplace_back(clause);
|
|
|
|
return single_query;
|
Make Where and NamedExpression macros easier to use
Summary:
`Where` can now be constructed in a `QUERY`, instead of requiring manual
addition to `Match`. For example:
auto query = QUERY(MATCH(pattern), WHERE(expr), ...);
compared to:
auto match = MATCH(pattern);
match->where_ = WHERE(expr);
auto query = QUERY(match, ...);
Similarly, `AS` can be used instead of `NEXPR` to create
`NamedExpressions` only with a name. This is meant to be used with
`RETURN` which will look at the previous `Expression` and store it
inside `NamedExpression`. For example:
auto ret = RETURN(IDENT("n"), AS("n"),
PROPERTY_LOOKUP("n", prop), AS("prop_val"));
compared to:
auto ret = RETURN(NEXPR("n", IDENT("n")),
NEXPR("prop_val", PROPERTY_LOOKUP("n", prop)));
Reviewers: florijan, mislav.bradac
Reviewed By: florijan
Subscribers: pullbot
Differential Revision: https://phabricator.memgraph.io/D195
2017-03-28 21:39:18 +08:00
|
|
|
}
|
2017-11-29 20:55:02 +08:00
|
|
|
auto GetSingleQuery(SingleQuery *single_query, Match *match, Where *where) {
|
2017-04-05 20:19:14 +08:00
|
|
|
match->where_ = where;
|
2017-11-29 20:55:02 +08:00
|
|
|
single_query->clauses_.emplace_back(match);
|
|
|
|
return single_query;
|
2017-04-05 20:19:14 +08:00
|
|
|
}
|
2017-11-29 20:55:02 +08:00
|
|
|
auto GetSingleQuery(SingleQuery *single_query, With *with, Where *where) {
|
2017-04-05 20:19:14 +08:00
|
|
|
with->where_ = where;
|
2017-11-29 20:55:02 +08:00
|
|
|
single_query->clauses_.emplace_back(with);
|
|
|
|
return single_query;
|
Make Where and NamedExpression macros easier to use
Summary:
`Where` can now be constructed in a `QUERY`, instead of requiring manual
addition to `Match`. For example:
auto query = QUERY(MATCH(pattern), WHERE(expr), ...);
compared to:
auto match = MATCH(pattern);
match->where_ = WHERE(expr);
auto query = QUERY(match, ...);
Similarly, `AS` can be used instead of `NEXPR` to create
`NamedExpressions` only with a name. This is meant to be used with
`RETURN` which will look at the previous `Expression` and store it
inside `NamedExpression`. For example:
auto ret = RETURN(IDENT("n"), AS("n"),
PROPERTY_LOOKUP("n", prop), AS("prop_val"));
compared to:
auto ret = RETURN(NEXPR("n", IDENT("n")),
NEXPR("prop_val", PROPERTY_LOOKUP("n", prop)));
Reviewers: florijan, mislav.bradac
Reviewed By: florijan
Subscribers: pullbot
Differential Revision: https://phabricator.memgraph.io/D195
2017-03-28 21:39:18 +08:00
|
|
|
}
|
|
|
|
template <class... T>
|
2017-11-29 20:55:02 +08:00
|
|
|
auto GetSingleQuery(SingleQuery *single_query, Match *match, Where *where,
|
|
|
|
T *... clauses) {
|
Make Where and NamedExpression macros easier to use
Summary:
`Where` can now be constructed in a `QUERY`, instead of requiring manual
addition to `Match`. For example:
auto query = QUERY(MATCH(pattern), WHERE(expr), ...);
compared to:
auto match = MATCH(pattern);
match->where_ = WHERE(expr);
auto query = QUERY(match, ...);
Similarly, `AS` can be used instead of `NEXPR` to create
`NamedExpressions` only with a name. This is meant to be used with
`RETURN` which will look at the previous `Expression` and store it
inside `NamedExpression`. For example:
auto ret = RETURN(IDENT("n"), AS("n"),
PROPERTY_LOOKUP("n", prop), AS("prop_val"));
compared to:
auto ret = RETURN(NEXPR("n", IDENT("n")),
NEXPR("prop_val", PROPERTY_LOOKUP("n", prop)));
Reviewers: florijan, mislav.bradac
Reviewed By: florijan
Subscribers: pullbot
Differential Revision: https://phabricator.memgraph.io/D195
2017-03-28 21:39:18 +08:00
|
|
|
match->where_ = where;
|
2017-11-29 20:55:02 +08:00
|
|
|
single_query->clauses_.emplace_back(match);
|
|
|
|
return GetSingleQuery(single_query, clauses...);
|
2017-03-24 23:50:42 +08:00
|
|
|
}
|
2017-04-05 20:19:14 +08:00
|
|
|
template <class... T>
|
2017-11-29 20:55:02 +08:00
|
|
|
auto GetSingleQuery(SingleQuery *single_query, With *with, Where *where,
|
|
|
|
T *... clauses) {
|
2017-04-05 20:19:14 +08:00
|
|
|
with->where_ = where;
|
2017-11-29 20:55:02 +08:00
|
|
|
single_query->clauses_.emplace_back(with);
|
|
|
|
return GetSingleQuery(single_query, clauses...);
|
2017-04-05 20:19:14 +08:00
|
|
|
}
|
2017-11-29 20:55:02 +08:00
|
|
|
|
|
|
|
template <class... T>
|
|
|
|
auto GetSingleQuery(SingleQuery *single_query, Clause *clause, T *... clauses) {
|
|
|
|
single_query->clauses_.emplace_back(clause);
|
|
|
|
return GetSingleQuery(single_query, clauses...);
|
|
|
|
}
|
|
|
|
|
|
|
|
auto GetCypherUnion(CypherUnion *cypher_union, SingleQuery *single_query) {
|
|
|
|
cypher_union->single_query_ = single_query;
|
|
|
|
return cypher_union;
|
|
|
|
}
|
|
|
|
|
2018-05-22 22:45:52 +08:00
|
|
|
auto GetQuery(AstStorage &storage, SingleQuery *single_query) {
|
2017-11-29 20:55:02 +08:00
|
|
|
storage.query()->single_query_ = single_query;
|
|
|
|
return storage.query();
|
|
|
|
}
|
|
|
|
|
2018-05-22 22:45:52 +08:00
|
|
|
auto GetQuery(AstStorage &storage, SingleQuery *single_query,
|
2017-11-29 20:55:02 +08:00
|
|
|
CypherUnion *cypher_union) {
|
|
|
|
storage.query()->cypher_unions_.emplace_back(cypher_union);
|
|
|
|
return GetQuery(storage, single_query);
|
|
|
|
}
|
|
|
|
|
2017-04-05 20:19:14 +08:00
|
|
|
template <class... T>
|
2018-05-22 22:45:52 +08:00
|
|
|
auto GetQuery(AstStorage &storage, SingleQuery *single_query,
|
2017-11-29 20:55:02 +08:00
|
|
|
CypherUnion *cypher_union, T *... cypher_unions) {
|
|
|
|
storage.query()->cypher_unions_.emplace_back(cypher_union);
|
|
|
|
return GetQuery(storage, single_query, cypher_unions...);
|
2017-04-05 20:19:14 +08:00
|
|
|
}
|
2017-03-24 23:50:42 +08:00
|
|
|
|
2017-04-24 19:51:16 +08:00
|
|
|
// Helper functions for constructing RETURN and WITH clauses.
|
2018-05-22 22:45:52 +08:00
|
|
|
void FillReturnBody(AstStorage &, ReturnBody &body,
|
2017-05-31 20:00:30 +08:00
|
|
|
NamedExpression *named_expr) {
|
|
|
|
body.named_expressions.emplace_back(named_expr);
|
|
|
|
}
|
2018-05-22 22:45:52 +08:00
|
|
|
void FillReturnBody(AstStorage &storage, ReturnBody &body,
|
2017-05-31 20:00:30 +08:00
|
|
|
const std::string &name) {
|
|
|
|
auto *ident = storage.Create<query::Identifier>(name);
|
|
|
|
auto *named_expr = storage.Create<query::NamedExpression>(name, ident);
|
2017-04-24 19:51:16 +08:00
|
|
|
body.named_expressions.emplace_back(named_expr);
|
Make Where and NamedExpression macros easier to use
Summary:
`Where` can now be constructed in a `QUERY`, instead of requiring manual
addition to `Match`. For example:
auto query = QUERY(MATCH(pattern), WHERE(expr), ...);
compared to:
auto match = MATCH(pattern);
match->where_ = WHERE(expr);
auto query = QUERY(match, ...);
Similarly, `AS` can be used instead of `NEXPR` to create
`NamedExpressions` only with a name. This is meant to be used with
`RETURN` which will look at the previous `Expression` and store it
inside `NamedExpression`. For example:
auto ret = RETURN(IDENT("n"), AS("n"),
PROPERTY_LOOKUP("n", prop), AS("prop_val"));
compared to:
auto ret = RETURN(NEXPR("n", IDENT("n")),
NEXPR("prop_val", PROPERTY_LOOKUP("n", prop)));
Reviewers: florijan, mislav.bradac
Reviewed By: florijan
Subscribers: pullbot
Differential Revision: https://phabricator.memgraph.io/D195
2017-03-28 21:39:18 +08:00
|
|
|
}
|
2018-05-22 22:45:52 +08:00
|
|
|
void FillReturnBody(AstStorage &, ReturnBody &body, Limit limit) {
|
2017-04-24 19:51:16 +08:00
|
|
|
body.limit = limit.expression;
|
2017-04-20 17:20:20 +08:00
|
|
|
}
|
2018-05-22 22:45:52 +08:00
|
|
|
void FillReturnBody(AstStorage &, ReturnBody &body, Skip skip,
|
2017-05-31 20:00:30 +08:00
|
|
|
Limit limit = Limit{}) {
|
2017-04-24 19:51:16 +08:00
|
|
|
body.skip = skip.expression;
|
|
|
|
body.limit = limit.expression;
|
|
|
|
}
|
2018-05-22 22:45:52 +08:00
|
|
|
void FillReturnBody(AstStorage &, ReturnBody &body, OrderBy order_by,
|
2017-05-31 20:00:30 +08:00
|
|
|
Limit limit = Limit{}) {
|
2017-04-24 19:51:16 +08:00
|
|
|
body.order_by = order_by.expressions;
|
|
|
|
body.limit = limit.expression;
|
|
|
|
}
|
2018-06-28 22:58:33 +08:00
|
|
|
void FillReturnBody(AstStorage &, ReturnBody &body, OrderBy order_by, Skip skip,
|
|
|
|
Limit limit = Limit{}) {
|
2017-04-24 19:51:16 +08:00
|
|
|
body.order_by = order_by.expressions;
|
|
|
|
body.skip = skip.expression;
|
|
|
|
body.limit = limit.expression;
|
2017-04-20 17:20:20 +08:00
|
|
|
}
|
2018-05-22 22:45:52 +08:00
|
|
|
void FillReturnBody(AstStorage &, ReturnBody &body, Expression *expr,
|
2017-04-24 19:51:16 +08:00
|
|
|
NamedExpression *named_expr) {
|
Make Where and NamedExpression macros easier to use
Summary:
`Where` can now be constructed in a `QUERY`, instead of requiring manual
addition to `Match`. For example:
auto query = QUERY(MATCH(pattern), WHERE(expr), ...);
compared to:
auto match = MATCH(pattern);
match->where_ = WHERE(expr);
auto query = QUERY(match, ...);
Similarly, `AS` can be used instead of `NEXPR` to create
`NamedExpressions` only with a name. This is meant to be used with
`RETURN` which will look at the previous `Expression` and store it
inside `NamedExpression`. For example:
auto ret = RETURN(IDENT("n"), AS("n"),
PROPERTY_LOOKUP("n", prop), AS("prop_val"));
compared to:
auto ret = RETURN(NEXPR("n", IDENT("n")),
NEXPR("prop_val", PROPERTY_LOOKUP("n", prop)));
Reviewers: florijan, mislav.bradac
Reviewed By: florijan
Subscribers: pullbot
Differential Revision: https://phabricator.memgraph.io/D195
2017-03-28 21:39:18 +08:00
|
|
|
// This overload supports `RETURN(expr, AS(name))` construct, since
|
|
|
|
// NamedExpression does not inherit Expression.
|
|
|
|
named_expr->expression_ = expr;
|
2017-04-24 19:51:16 +08:00
|
|
|
body.named_expressions.emplace_back(named_expr);
|
2017-03-24 23:50:42 +08:00
|
|
|
}
|
2018-05-22 22:45:52 +08:00
|
|
|
void FillReturnBody(AstStorage &storage, ReturnBody &body,
|
2017-05-31 20:00:30 +08:00
|
|
|
const std::string &name, NamedExpression *named_expr) {
|
|
|
|
named_expr->expression_ = storage.Create<query::Identifier>(name);
|
|
|
|
body.named_expressions.emplace_back(named_expr);
|
|
|
|
}
|
Make Where and NamedExpression macros easier to use
Summary:
`Where` can now be constructed in a `QUERY`, instead of requiring manual
addition to `Match`. For example:
auto query = QUERY(MATCH(pattern), WHERE(expr), ...);
compared to:
auto match = MATCH(pattern);
match->where_ = WHERE(expr);
auto query = QUERY(match, ...);
Similarly, `AS` can be used instead of `NEXPR` to create
`NamedExpressions` only with a name. This is meant to be used with
`RETURN` which will look at the previous `Expression` and store it
inside `NamedExpression`. For example:
auto ret = RETURN(IDENT("n"), AS("n"),
PROPERTY_LOOKUP("n", prop), AS("prop_val"));
compared to:
auto ret = RETURN(NEXPR("n", IDENT("n")),
NEXPR("prop_val", PROPERTY_LOOKUP("n", prop)));
Reviewers: florijan, mislav.bradac
Reviewed By: florijan
Subscribers: pullbot
Differential Revision: https://phabricator.memgraph.io/D195
2017-03-28 21:39:18 +08:00
|
|
|
template <class... T>
|
2018-05-22 22:45:52 +08:00
|
|
|
void FillReturnBody(AstStorage &storage, ReturnBody &body, Expression *expr,
|
2017-04-24 19:51:16 +08:00
|
|
|
NamedExpression *named_expr, T... rest) {
|
Make Where and NamedExpression macros easier to use
Summary:
`Where` can now be constructed in a `QUERY`, instead of requiring manual
addition to `Match`. For example:
auto query = QUERY(MATCH(pattern), WHERE(expr), ...);
compared to:
auto match = MATCH(pattern);
match->where_ = WHERE(expr);
auto query = QUERY(match, ...);
Similarly, `AS` can be used instead of `NEXPR` to create
`NamedExpressions` only with a name. This is meant to be used with
`RETURN` which will look at the previous `Expression` and store it
inside `NamedExpression`. For example:
auto ret = RETURN(IDENT("n"), AS("n"),
PROPERTY_LOOKUP("n", prop), AS("prop_val"));
compared to:
auto ret = RETURN(NEXPR("n", IDENT("n")),
NEXPR("prop_val", PROPERTY_LOOKUP("n", prop)));
Reviewers: florijan, mislav.bradac
Reviewed By: florijan
Subscribers: pullbot
Differential Revision: https://phabricator.memgraph.io/D195
2017-03-28 21:39:18 +08:00
|
|
|
named_expr->expression_ = expr;
|
2017-04-24 19:51:16 +08:00
|
|
|
body.named_expressions.emplace_back(named_expr);
|
2017-05-31 20:00:30 +08:00
|
|
|
FillReturnBody(storage, body, rest...);
|
|
|
|
}
|
|
|
|
template <class... T>
|
2018-05-22 22:45:52 +08:00
|
|
|
void FillReturnBody(AstStorage &storage, ReturnBody &body,
|
2017-05-31 20:00:30 +08:00
|
|
|
NamedExpression *named_expr, T... rest) {
|
|
|
|
body.named_expressions.emplace_back(named_expr);
|
|
|
|
FillReturnBody(storage, body, rest...);
|
|
|
|
}
|
|
|
|
template <class... T>
|
2018-05-22 22:45:52 +08:00
|
|
|
void FillReturnBody(AstStorage &storage, ReturnBody &body,
|
2017-05-31 20:00:30 +08:00
|
|
|
const std::string &name, NamedExpression *named_expr,
|
|
|
|
T... rest) {
|
|
|
|
named_expr->expression_ = storage.Create<query::Identifier>(name);
|
|
|
|
body.named_expressions.emplace_back(named_expr);
|
|
|
|
FillReturnBody(storage, body, rest...);
|
Make Where and NamedExpression macros easier to use
Summary:
`Where` can now be constructed in a `QUERY`, instead of requiring manual
addition to `Match`. For example:
auto query = QUERY(MATCH(pattern), WHERE(expr), ...);
compared to:
auto match = MATCH(pattern);
match->where_ = WHERE(expr);
auto query = QUERY(match, ...);
Similarly, `AS` can be used instead of `NEXPR` to create
`NamedExpressions` only with a name. This is meant to be used with
`RETURN` which will look at the previous `Expression` and store it
inside `NamedExpression`. For example:
auto ret = RETURN(IDENT("n"), AS("n"),
PROPERTY_LOOKUP("n", prop), AS("prop_val"));
compared to:
auto ret = RETURN(NEXPR("n", IDENT("n")),
NEXPR("prop_val", PROPERTY_LOOKUP("n", prop)));
Reviewers: florijan, mislav.bradac
Reviewed By: florijan
Subscribers: pullbot
Differential Revision: https://phabricator.memgraph.io/D195
2017-03-28 21:39:18 +08:00
|
|
|
}
|
|
|
|
template <class... T>
|
2018-05-22 22:45:52 +08:00
|
|
|
void FillReturnBody(AstStorage &storage, ReturnBody &body,
|
2017-05-31 20:00:30 +08:00
|
|
|
const std::string &name, T... rest) {
|
|
|
|
auto *ident = storage.Create<query::Identifier>(name);
|
|
|
|
auto *named_expr = storage.Create<query::NamedExpression>(name, ident);
|
2017-04-24 19:51:16 +08:00
|
|
|
body.named_expressions.emplace_back(named_expr);
|
2017-05-31 20:00:30 +08:00
|
|
|
FillReturnBody(storage, body, rest...);
|
Make Where and NamedExpression macros easier to use
Summary:
`Where` can now be constructed in a `QUERY`, instead of requiring manual
addition to `Match`. For example:
auto query = QUERY(MATCH(pattern), WHERE(expr), ...);
compared to:
auto match = MATCH(pattern);
match->where_ = WHERE(expr);
auto query = QUERY(match, ...);
Similarly, `AS` can be used instead of `NEXPR` to create
`NamedExpressions` only with a name. This is meant to be used with
`RETURN` which will look at the previous `Expression` and store it
inside `NamedExpression`. For example:
auto ret = RETURN(IDENT("n"), AS("n"),
PROPERTY_LOOKUP("n", prop), AS("prop_val"));
compared to:
auto ret = RETURN(NEXPR("n", IDENT("n")),
NEXPR("prop_val", PROPERTY_LOOKUP("n", prop)));
Reviewers: florijan, mislav.bradac
Reviewed By: florijan
Subscribers: pullbot
Differential Revision: https://phabricator.memgraph.io/D195
2017-03-28 21:39:18 +08:00
|
|
|
}
|
2017-04-24 19:51:16 +08:00
|
|
|
|
|
|
|
/// Create the return clause with given expressions.
|
|
|
|
///
|
|
|
|
/// The supported expression combination of arguments is:
|
|
|
|
///
|
2017-05-31 20:00:30 +08:00
|
|
|
/// (String | NamedExpression | (Expression NamedExpression))+
|
|
|
|
/// [OrderBy] [Skip] [Limit]
|
2017-04-24 19:51:16 +08:00
|
|
|
///
|
|
|
|
/// When the pair (Expression NamedExpression) is given, the Expression will be
|
|
|
|
/// moved inside the NamedExpression. This is done, so that the constructs like
|
2017-05-31 20:00:30 +08:00
|
|
|
/// RETURN(expr, AS("name"), ...) are supported. Taking a String is a shorthand
|
|
|
|
/// for RETURN(IDENT(string), AS(string), ....).
|
2017-04-24 19:51:16 +08:00
|
|
|
///
|
|
|
|
/// @sa GetWith
|
Make Where and NamedExpression macros easier to use
Summary:
`Where` can now be constructed in a `QUERY`, instead of requiring manual
addition to `Match`. For example:
auto query = QUERY(MATCH(pattern), WHERE(expr), ...);
compared to:
auto match = MATCH(pattern);
match->where_ = WHERE(expr);
auto query = QUERY(match, ...);
Similarly, `AS` can be used instead of `NEXPR` to create
`NamedExpressions` only with a name. This is meant to be used with
`RETURN` which will look at the previous `Expression` and store it
inside `NamedExpression`. For example:
auto ret = RETURN(IDENT("n"), AS("n"),
PROPERTY_LOOKUP("n", prop), AS("prop_val"));
compared to:
auto ret = RETURN(NEXPR("n", IDENT("n")),
NEXPR("prop_val", PROPERTY_LOOKUP("n", prop)));
Reviewers: florijan, mislav.bradac
Reviewed By: florijan
Subscribers: pullbot
Differential Revision: https://phabricator.memgraph.io/D195
2017-03-28 21:39:18 +08:00
|
|
|
template <class... T>
|
2018-05-22 22:45:52 +08:00
|
|
|
auto GetReturn(AstStorage &storage, bool distinct, T... exprs) {
|
Make Where and NamedExpression macros easier to use
Summary:
`Where` can now be constructed in a `QUERY`, instead of requiring manual
addition to `Match`. For example:
auto query = QUERY(MATCH(pattern), WHERE(expr), ...);
compared to:
auto match = MATCH(pattern);
match->where_ = WHERE(expr);
auto query = QUERY(match, ...);
Similarly, `AS` can be used instead of `NEXPR` to create
`NamedExpressions` only with a name. This is meant to be used with
`RETURN` which will look at the previous `Expression` and store it
inside `NamedExpression`. For example:
auto ret = RETURN(IDENT("n"), AS("n"),
PROPERTY_LOOKUP("n", prop), AS("prop_val"));
compared to:
auto ret = RETURN(NEXPR("n", IDENT("n")),
NEXPR("prop_val", PROPERTY_LOOKUP("n", prop)));
Reviewers: florijan, mislav.bradac
Reviewed By: florijan
Subscribers: pullbot
Differential Revision: https://phabricator.memgraph.io/D195
2017-03-28 21:39:18 +08:00
|
|
|
auto ret = storage.Create<Return>();
|
2017-05-03 20:57:46 +08:00
|
|
|
ret->body_.distinct = distinct;
|
2017-05-31 20:00:30 +08:00
|
|
|
FillReturnBody(storage, ret->body_, exprs...);
|
2017-04-24 19:51:16 +08:00
|
|
|
return ret;
|
Make Where and NamedExpression macros easier to use
Summary:
`Where` can now be constructed in a `QUERY`, instead of requiring manual
addition to `Match`. For example:
auto query = QUERY(MATCH(pattern), WHERE(expr), ...);
compared to:
auto match = MATCH(pattern);
match->where_ = WHERE(expr);
auto query = QUERY(match, ...);
Similarly, `AS` can be used instead of `NEXPR` to create
`NamedExpressions` only with a name. This is meant to be used with
`RETURN` which will look at the previous `Expression` and store it
inside `NamedExpression`. For example:
auto ret = RETURN(IDENT("n"), AS("n"),
PROPERTY_LOOKUP("n", prop), AS("prop_val"));
compared to:
auto ret = RETURN(NEXPR("n", IDENT("n")),
NEXPR("prop_val", PROPERTY_LOOKUP("n", prop)));
Reviewers: florijan, mislav.bradac
Reviewed By: florijan
Subscribers: pullbot
Differential Revision: https://phabricator.memgraph.io/D195
2017-03-28 21:39:18 +08:00
|
|
|
}
|
2017-03-24 23:50:42 +08:00
|
|
|
|
2017-04-24 19:51:16 +08:00
|
|
|
/// Create the with clause with given expressions.
|
2017-04-05 20:19:14 +08:00
|
|
|
///
|
2017-04-24 19:51:16 +08:00
|
|
|
/// The supported expression combination is the same as for @c GetReturn.
|
|
|
|
///
|
|
|
|
/// @sa GetReturn
|
2017-04-05 20:19:14 +08:00
|
|
|
template <class... T>
|
2018-05-22 22:45:52 +08:00
|
|
|
auto GetWith(AstStorage &storage, bool distinct, T... exprs) {
|
2017-04-05 20:19:14 +08:00
|
|
|
auto with = storage.Create<With>();
|
2017-05-03 20:57:46 +08:00
|
|
|
with->body_.distinct = distinct;
|
2017-05-31 20:00:30 +08:00
|
|
|
FillReturnBody(storage, with->body_, exprs...);
|
2017-04-24 19:51:16 +08:00
|
|
|
return with;
|
2017-04-05 20:19:14 +08:00
|
|
|
}
|
|
|
|
|
2017-05-02 21:21:04 +08:00
|
|
|
/// Create the UNWIND clause with given named expression.
|
2018-05-22 22:45:52 +08:00
|
|
|
auto GetUnwind(AstStorage &storage, NamedExpression *named_expr) {
|
2017-05-02 21:21:04 +08:00
|
|
|
return storage.Create<query::Unwind>(named_expr);
|
|
|
|
}
|
2018-05-22 22:45:52 +08:00
|
|
|
auto GetUnwind(AstStorage &storage, Expression *expr, NamedExpression *as) {
|
2017-05-02 21:21:04 +08:00
|
|
|
as->expression_ = expr;
|
|
|
|
return GetUnwind(storage, as);
|
|
|
|
}
|
|
|
|
|
2017-03-27 20:23:31 +08:00
|
|
|
/// Create the delete clause with given named expressions.
|
2018-05-22 22:45:52 +08:00
|
|
|
auto GetDelete(AstStorage &storage, std::vector<Expression *> exprs,
|
2017-03-27 20:23:31 +08:00
|
|
|
bool detach = false) {
|
|
|
|
auto del = storage.Create<Delete>();
|
|
|
|
del->expressions_.insert(del->expressions_.begin(), exprs.begin(),
|
|
|
|
exprs.end());
|
|
|
|
del->detach_ = detach;
|
|
|
|
return del;
|
|
|
|
}
|
|
|
|
|
2017-03-28 17:04:28 +08:00
|
|
|
/// Create a set property clause for given property lookup and the right hand
|
|
|
|
/// side expression.
|
2018-05-22 22:45:52 +08:00
|
|
|
auto GetSet(AstStorage &storage, PropertyLookup *prop_lookup,
|
2017-03-28 17:04:28 +08:00
|
|
|
Expression *expr) {
|
|
|
|
return storage.Create<SetProperty>(prop_lookup, expr);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Create a set properties clause for given identifier name and the right hand
|
|
|
|
/// side expression.
|
2018-05-22 22:45:52 +08:00
|
|
|
auto GetSet(AstStorage &storage, const std::string &name, Expression *expr,
|
2017-03-28 17:04:28 +08:00
|
|
|
bool update = false) {
|
|
|
|
return storage.Create<SetProperties>(storage.Create<Identifier>(name), expr,
|
|
|
|
update);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Create a set labels clause for given identifier name and labels.
|
2018-05-22 22:45:52 +08:00
|
|
|
auto GetSet(AstStorage &storage, const std::string &name,
|
2018-01-16 17:09:15 +08:00
|
|
|
std::vector<storage::Label> labels) {
|
2017-03-28 17:04:28 +08:00
|
|
|
return storage.Create<SetLabels>(storage.Create<Identifier>(name), labels);
|
|
|
|
}
|
|
|
|
|
2017-03-30 14:44:56 +08:00
|
|
|
/// Create a remove property clause for given property lookup
|
2018-05-22 22:45:52 +08:00
|
|
|
auto GetRemove(AstStorage &storage, PropertyLookup *prop_lookup) {
|
2017-03-30 14:44:56 +08:00
|
|
|
return storage.Create<RemoveProperty>(prop_lookup);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Create a remove labels clause for given identifier name and labels.
|
2018-05-22 22:45:52 +08:00
|
|
|
auto GetRemove(AstStorage &storage, const std::string &name,
|
2018-01-16 17:09:15 +08:00
|
|
|
std::vector<storage::Label> labels) {
|
2017-03-30 14:44:56 +08:00
|
|
|
return storage.Create<RemoveLabels>(storage.Create<Identifier>(name), labels);
|
|
|
|
}
|
|
|
|
|
2017-04-26 19:49:41 +08:00
|
|
|
/// Create a Merge clause for given Pattern with optional OnMatch and OnCreate
|
|
|
|
/// parts.
|
2018-05-22 22:45:52 +08:00
|
|
|
auto GetMerge(AstStorage &storage, Pattern *pattern,
|
2017-04-26 19:49:41 +08:00
|
|
|
OnCreate on_create = OnCreate{}) {
|
|
|
|
auto *merge = storage.Create<query::Merge>();
|
|
|
|
merge->pattern_ = pattern;
|
|
|
|
merge->on_create_ = on_create.set;
|
|
|
|
return merge;
|
|
|
|
}
|
2018-05-22 22:45:52 +08:00
|
|
|
auto GetMerge(AstStorage &storage, Pattern *pattern, OnMatch on_match,
|
2017-04-26 19:49:41 +08:00
|
|
|
OnCreate on_create = OnCreate{}) {
|
|
|
|
auto *merge = storage.Create<query::Merge>();
|
|
|
|
merge->pattern_ = pattern;
|
|
|
|
merge->on_match_ = on_match.set;
|
|
|
|
merge->on_create_ = on_create.set;
|
|
|
|
return merge;
|
|
|
|
}
|
|
|
|
|
2017-03-24 23:50:42 +08:00
|
|
|
} // namespace test_common
|
|
|
|
|
|
|
|
} // namespace query
|
|
|
|
|
|
|
|
/// All the following macros implicitly pass `storage` variable to functions.
|
2018-05-22 22:45:52 +08:00
|
|
|
/// You need to have `AstStorage storage;` somewhere in scope to use them.
|
2017-03-24 23:50:42 +08:00
|
|
|
/// Refer to function documentation to see what the macro does.
|
|
|
|
///
|
|
|
|
/// Example usage:
|
|
|
|
///
|
|
|
|
/// // Create MATCH (n) -[r]- (m) RETURN m AS new_name
|
2018-05-22 22:45:52 +08:00
|
|
|
/// AstStorage storage;
|
2017-03-24 23:50:42 +08:00
|
|
|
/// auto query = QUERY(MATCH(PATTERN(NODE("n"), EDGE("r"), NODE("m"))),
|
|
|
|
/// RETURN(NEXPR("new_name"), IDENT("m")));
|
|
|
|
#define NODE(...) query::test_common::GetNode(storage, __VA_ARGS__)
|
|
|
|
#define EDGE(...) query::test_common::GetEdge(storage, __VA_ARGS__)
|
2017-10-05 17:25:52 +08:00
|
|
|
#define EDGE_VARIABLE(...) \
|
|
|
|
query::test_common::GetEdgeVariable(storage, __VA_ARGS__)
|
2017-03-24 23:50:42 +08:00
|
|
|
#define PATTERN(...) query::test_common::GetPattern(storage, {__VA_ARGS__})
|
2017-09-18 20:40:36 +08:00
|
|
|
#define NAMED_PATTERN(name, ...) \
|
|
|
|
query::test_common::GetPattern(storage, name, {__VA_ARGS__})
|
2017-04-28 16:37:49 +08:00
|
|
|
#define OPTIONAL_MATCH(...) \
|
|
|
|
query::test_common::GetWithPatterns(storage.Create<query::Match>(true), \
|
|
|
|
{__VA_ARGS__})
|
|
|
|
#define MATCH(...) \
|
|
|
|
query::test_common::GetWithPatterns(storage.Create<query::Match>(), \
|
|
|
|
{__VA_ARGS__})
|
2017-03-27 18:10:50 +08:00
|
|
|
#define WHERE(expr) storage.Create<query::Where>((expr))
|
2017-04-28 16:37:49 +08:00
|
|
|
#define CREATE(...) \
|
|
|
|
query::test_common::GetWithPatterns(storage.Create<query::Create>(), \
|
|
|
|
{__VA_ARGS__})
|
2017-03-27 19:09:14 +08:00
|
|
|
#define IDENT(name) storage.Create<query::Identifier>((name))
|
2017-04-28 18:06:18 +08:00
|
|
|
#define LITERAL(val) storage.Create<query::PrimitiveLiteral>((val))
|
2017-05-02 21:21:04 +08:00
|
|
|
#define LIST(...) \
|
|
|
|
storage.Create<query::ListLiteral>( \
|
|
|
|
std::vector<query::Expression *>{__VA_ARGS__})
|
2018-01-16 17:09:15 +08:00
|
|
|
#define MAP(...) \
|
|
|
|
storage.Create<query::MapLiteral>( \
|
|
|
|
std::unordered_map<std::pair<std::string, storage::Property>, \
|
2017-10-02 16:34:38 +08:00
|
|
|
query::Expression *>{__VA_ARGS__})
|
2017-08-08 19:43:42 +08:00
|
|
|
#define PROPERTY_PAIR(property_name) \
|
2018-06-19 19:52:11 +08:00
|
|
|
std::make_pair(property_name, dba.Property(property_name))
|
2017-03-27 18:10:50 +08:00
|
|
|
#define PROPERTY_LOOKUP(...) \
|
2018-06-19 19:52:11 +08:00
|
|
|
query::test_common::GetPropertyLookup(storage, dba, __VA_ARGS__)
|
2018-09-28 22:29:27 +08:00
|
|
|
#define PARAMETER_LOOKUP(token_position) \
|
|
|
|
storage.Create<query::ParameterLookup>((token_position))
|
2017-03-27 19:09:14 +08:00
|
|
|
#define NEXPR(name, expr) storage.Create<query::NamedExpression>((name), (expr))
|
Make Where and NamedExpression macros easier to use
Summary:
`Where` can now be constructed in a `QUERY`, instead of requiring manual
addition to `Match`. For example:
auto query = QUERY(MATCH(pattern), WHERE(expr), ...);
compared to:
auto match = MATCH(pattern);
match->where_ = WHERE(expr);
auto query = QUERY(match, ...);
Similarly, `AS` can be used instead of `NEXPR` to create
`NamedExpressions` only with a name. This is meant to be used with
`RETURN` which will look at the previous `Expression` and store it
inside `NamedExpression`. For example:
auto ret = RETURN(IDENT("n"), AS("n"),
PROPERTY_LOOKUP("n", prop), AS("prop_val"));
compared to:
auto ret = RETURN(NEXPR("n", IDENT("n")),
NEXPR("prop_val", PROPERTY_LOOKUP("n", prop)));
Reviewers: florijan, mislav.bradac
Reviewed By: florijan
Subscribers: pullbot
Differential Revision: https://phabricator.memgraph.io/D195
2017-03-28 21:39:18 +08:00
|
|
|
// AS is alternative to NEXPR which does not initialize NamedExpression with
|
2017-04-05 20:19:14 +08:00
|
|
|
// Expression. It should be used with RETURN or WITH. For example:
|
Make Where and NamedExpression macros easier to use
Summary:
`Where` can now be constructed in a `QUERY`, instead of requiring manual
addition to `Match`. For example:
auto query = QUERY(MATCH(pattern), WHERE(expr), ...);
compared to:
auto match = MATCH(pattern);
match->where_ = WHERE(expr);
auto query = QUERY(match, ...);
Similarly, `AS` can be used instead of `NEXPR` to create
`NamedExpressions` only with a name. This is meant to be used with
`RETURN` which will look at the previous `Expression` and store it
inside `NamedExpression`. For example:
auto ret = RETURN(IDENT("n"), AS("n"),
PROPERTY_LOOKUP("n", prop), AS("prop_val"));
compared to:
auto ret = RETURN(NEXPR("n", IDENT("n")),
NEXPR("prop_val", PROPERTY_LOOKUP("n", prop)));
Reviewers: florijan, mislav.bradac
Reviewed By: florijan
Subscribers: pullbot
Differential Revision: https://phabricator.memgraph.io/D195
2017-03-28 21:39:18 +08:00
|
|
|
// RETURN(IDENT("n"), AS("n")) vs. RETURN(NEXPR("n", IDENT("n"))).
|
|
|
|
#define AS(name) storage.Create<query::NamedExpression>((name))
|
2017-05-03 20:57:46 +08:00
|
|
|
#define RETURN(...) query::test_common::GetReturn(storage, false, __VA_ARGS__)
|
|
|
|
#define WITH(...) query::test_common::GetWith(storage, false, __VA_ARGS__)
|
|
|
|
#define RETURN_DISTINCT(...) \
|
|
|
|
query::test_common::GetReturn(storage, true, __VA_ARGS__)
|
|
|
|
#define WITH_DISTINCT(...) \
|
|
|
|
query::test_common::GetWith(storage, true, __VA_ARGS__)
|
2017-05-02 21:21:04 +08:00
|
|
|
#define UNWIND(...) query::test_common::GetUnwind(storage, __VA_ARGS__)
|
2017-04-24 19:51:16 +08:00
|
|
|
#define ORDER_BY(...) query::test_common::GetOrderBy(__VA_ARGS__)
|
|
|
|
#define SKIP(expr) \
|
|
|
|
query::test_common::Skip { (expr) }
|
|
|
|
#define LIMIT(expr) \
|
|
|
|
query::test_common::Limit { (expr) }
|
2017-03-27 20:23:31 +08:00
|
|
|
#define DELETE(...) query::test_common::GetDelete(storage, {__VA_ARGS__})
|
|
|
|
#define DETACH_DELETE(...) \
|
|
|
|
query::test_common::GetDelete(storage, {__VA_ARGS__}, true)
|
2017-03-28 17:04:28 +08:00
|
|
|
#define SET(...) query::test_common::GetSet(storage, __VA_ARGS__)
|
2017-03-30 14:44:56 +08:00
|
|
|
#define REMOVE(...) query::test_common::GetRemove(storage, __VA_ARGS__)
|
2017-04-26 19:49:41 +08:00
|
|
|
#define MERGE(...) query::test_common::GetMerge(storage, __VA_ARGS__)
|
|
|
|
#define ON_MATCH(...) \
|
|
|
|
query::test_common::OnMatch { \
|
|
|
|
std::vector<query::Clause *> { __VA_ARGS__ } \
|
|
|
|
}
|
|
|
|
#define ON_CREATE(...) \
|
|
|
|
query::test_common::OnCreate { \
|
|
|
|
std::vector<query::Clause *> { __VA_ARGS__ } \
|
|
|
|
}
|
2017-07-06 17:32:28 +08:00
|
|
|
#define CREATE_INDEX_ON(label, property) \
|
|
|
|
storage.Create<query::CreateIndex>((label), (property))
|
Make Where and NamedExpression macros easier to use
Summary:
`Where` can now be constructed in a `QUERY`, instead of requiring manual
addition to `Match`. For example:
auto query = QUERY(MATCH(pattern), WHERE(expr), ...);
compared to:
auto match = MATCH(pattern);
match->where_ = WHERE(expr);
auto query = QUERY(match, ...);
Similarly, `AS` can be used instead of `NEXPR` to create
`NamedExpressions` only with a name. This is meant to be used with
`RETURN` which will look at the previous `Expression` and store it
inside `NamedExpression`. For example:
auto ret = RETURN(IDENT("n"), AS("n"),
PROPERTY_LOOKUP("n", prop), AS("prop_val"));
compared to:
auto ret = RETURN(NEXPR("n", IDENT("n")),
NEXPR("prop_val", PROPERTY_LOOKUP("n", prop)));
Reviewers: florijan, mislav.bradac
Reviewed By: florijan
Subscribers: pullbot
Differential Revision: https://phabricator.memgraph.io/D195
2017-03-28 21:39:18 +08:00
|
|
|
#define QUERY(...) query::test_common::GetQuery(storage, __VA_ARGS__)
|
2017-11-29 20:55:02 +08:00
|
|
|
#define SINGLE_QUERY(...) \
|
|
|
|
query::test_common::GetSingleQuery(storage.Create<SingleQuery>(), __VA_ARGS__)
|
|
|
|
#define UNION(...) \
|
|
|
|
query::test_common::GetCypherUnion(storage.Create<CypherUnion>(true), \
|
|
|
|
__VA_ARGS__)
|
|
|
|
#define UNION_ALL(...) \
|
|
|
|
query::test_common::GetCypherUnion(storage.Create<CypherUnion>(false), \
|
|
|
|
__VA_ARGS__)
|
2017-04-03 20:32:29 +08:00
|
|
|
// Various operators
|
2017-04-24 19:51:16 +08:00
|
|
|
#define ADD(expr1, expr2) \
|
|
|
|
storage.Create<query::AdditionOperator>((expr1), (expr2))
|
2017-03-27 18:10:50 +08:00
|
|
|
#define LESS(expr1, expr2) storage.Create<query::LessOperator>((expr1), (expr2))
|
2017-07-04 16:37:39 +08:00
|
|
|
#define LESS_EQ(expr1, expr2) \
|
|
|
|
storage.Create<query::LessEqualOperator>((expr1), (expr2))
|
|
|
|
#define GREATER(expr1, expr2) \
|
|
|
|
storage.Create<query::GreaterOperator>((expr1), (expr2))
|
|
|
|
#define GREATER_EQ(expr1, expr2) \
|
|
|
|
storage.Create<query::GreaterEqualOperator>((expr1), (expr2))
|
Collect Map added
Summary:
Tests are on the way. Please first comment if you're OK with this implementation, some points are discussable.
What works now:
```
bash:MEMGRAPH_ROOT/build/>./tests/manual/console 10
MG>MATCH (n) RETURN COLLECT("age_" + n.age, n.height)
+-----------------------------------------------------------------------------------------------------------------------------------+
| COLLECT("age_" + n.age, n.height) |
+-----------------------------------------------------------------------------------------------------------------------------------+
| {age_10: 176, age_13: 180, age_24: 172, age_25: 179, age_32: 123, age_33: 186, age_37: 147, age_43: 162, age_49: 126, age_6: 170} |
+-----------------------------------------------------------------------------------------------------------------------------------+
```
Reviewers: mislav.bradac, teon.banek, buda
Reviewed By: mislav.bradac, buda
Subscribers: pullbot
Differential Revision: https://phabricator.memgraph.io/D695
2017-08-23 16:43:45 +08:00
|
|
|
#define SUM(expr) \
|
|
|
|
storage.Create<query::Aggregation>((expr), nullptr, \
|
|
|
|
query::Aggregation::Op::SUM)
|
|
|
|
#define COUNT(expr) \
|
|
|
|
storage.Create<query::Aggregation>((expr), nullptr, \
|
|
|
|
query::Aggregation::Op::COUNT)
|
2018-01-31 17:38:36 +08:00
|
|
|
#define AVG(expr) \
|
|
|
|
storage.Create<query::Aggregation>((expr), nullptr, \
|
|
|
|
query::Aggregation::Op::AVG)
|
2018-02-13 20:58:01 +08:00
|
|
|
#define COLLECT_LIST(expr) \
|
|
|
|
storage.Create<query::Aggregation>((expr), nullptr, \
|
|
|
|
query::Aggregation::Op::COLLECT_LIST)
|
2017-05-05 21:34:07 +08:00
|
|
|
#define EQ(expr1, expr2) storage.Create<query::EqualOperator>((expr1), (expr2))
|
2017-08-08 19:43:42 +08:00
|
|
|
#define NEQ(expr1, expr2) \
|
|
|
|
storage.Create<query::NotEqualOperator>((expr1), (expr2))
|
2017-05-05 21:34:07 +08:00
|
|
|
#define AND(expr1, expr2) storage.Create<query::AndOperator>((expr1), (expr2))
|
|
|
|
#define OR(expr1, expr2) storage.Create<query::OrOperator>((expr1), (expr2))
|
Clean-up TypedValue misuse
Summary:
In a bunch of places `TypedValue` was used where `PropertyValue` should be. A lot of times it was only because `TypedValue` serialization code could be reused for `PropertyValue`, only without providing callbacks for `VERTEX`, `EDGE` and `PATH`. So first I wrote separate serialization code for `PropertyValue` and put it into storage folder. Then I fixed all the places where `TypedValue` was incorrectly used instead of `PropertyValue`. I also disabled implicit `TypedValue` to `PropertyValue` conversion in hopes of preventing misuse in the future.
After that, I wrote code for `VertexAccessor` and `EdgeAccessor` serialization and put it into `storage` folder because it was almost duplicated in distributed BFS and pull produce RPC messages. On the sender side, some subset of records (old or new or both) is serialized, and on the reciever side, records are deserialized and immediately put into transaction cache.
Then I rewrote the `TypedValue` serialization functions (`SaveCapnpTypedValue` and `LoadCapnpTypedValue`) to not take callbacks for `VERTEX`, `EDGE` and `PATH`, but use accessor serialization functions instead. That means that any code that wants to use `TypedValue` serialization must hold a reference to `GraphDbAccessor` and `DataManager`, so that should make clients reconsider if they really want to use `TypedValue` instead of `PropertyValue`.
Reviewers: teon.banek, msantl
Reviewed By: teon.banek
Subscribers: pullbot
Differential Revision: https://phabricator.memgraph.io/D1598
2018-09-13 18:12:07 +08:00
|
|
|
#define IN_LIST(expr1, expr2) \
|
|
|
|
storage.Create<query::InListOperator>((expr1), (expr2))
|
2018-09-28 22:29:27 +08:00
|
|
|
#define IF(cond, then, else) \
|
|
|
|
storage.Create<query::IfOperator>((cond), (then), (else))
|
2017-06-05 17:50:47 +08:00
|
|
|
// Function call
|
2017-12-20 18:24:48 +08:00
|
|
|
#define FN(function_name, ...) \
|
|
|
|
storage.Create<query::Function>( \
|
|
|
|
utils::ToUpperCase(function_name), \
|
2017-06-05 17:50:47 +08:00
|
|
|
std::vector<query::Expression *>{__VA_ARGS__})
|
|
|
|
// List slicing
|
|
|
|
#define SLICE(list, lower_bound, upper_bound) \
|
|
|
|
storage.Create<query::ListSlicingOperator>(list, lower_bound, upper_bound)
|
2017-07-25 19:01:08 +08:00
|
|
|
// all(variable IN list WHERE predicate)
|
|
|
|
#define ALL(variable, list, where) \
|
|
|
|
storage.Create<query::All>(storage.Create<query::Identifier>(variable), \
|
|
|
|
list, where)
|
2018-02-12 23:13:45 +08:00
|
|
|
#define SINGLE(variable, list, where) \
|
|
|
|
storage.Create<query::Single>(storage.Create<query::Identifier>(variable), \
|
|
|
|
list, where)
|
2018-02-07 17:57:38 +08:00
|
|
|
#define REDUCE(accumulator, initializer, variable, list, expr) \
|
|
|
|
storage.Create<query::Reduce>( \
|
|
|
|
storage.Create<query::Identifier>(accumulator), initializer, \
|
|
|
|
storage.Create<query::Identifier>(variable), list, expr)
|
2018-06-28 22:58:33 +08:00
|
|
|
#define EXTRACT(variable, list, expr) \
|
|
|
|
storage.Create<query::Extract>(storage.Create<query::Identifier>(variable), \
|
|
|
|
list, expr)
|
2018-08-06 21:16:39 +08:00
|
|
|
#define AUTH_QUERY(action, user, role, user_or_role, password, privileges) \
|
|
|
|
storage.Create<query::AuthQuery>((action), (user), (role), (user_or_role), \
|
2018-08-16 16:13:04 +08:00
|
|
|
password, (privileges))
|
2018-06-14 22:02:27 +08:00
|
|
|
#define DROP_USER(usernames) storage.Create<query::DropUser>((usernames))
|
2018-06-19 20:37:02 +08:00
|
|
|
#define CREATE_STREAM(stream_name, stream_uri, stream_topic, transform_uri, \
|
|
|
|
batch_interval, batch_size) \
|
|
|
|
storage.Create<query::CreateStream>( \
|
|
|
|
(stream_name), LITERAL(stream_uri), LITERAL(stream_topic), \
|
|
|
|
LITERAL(transform_uri), (batch_interval), (batch_size))
|
2018-06-15 22:12:44 +08:00
|
|
|
#define DROP_STREAM(stream_name) \
|
|
|
|
storage.Create<query::DropStream>((stream_name))
|
|
|
|
#define SHOW_STREAMS storage.Create<query::ShowStreams>()
|
|
|
|
#define START_STREAM(stream_name, limit_batches) \
|
2018-07-03 19:57:53 +08:00
|
|
|
storage.Create<query::StartStopStream>((stream_name), true, (limit_batches))
|
2018-06-15 22:12:44 +08:00
|
|
|
#define STOP_STREAM(stream_name) \
|
|
|
|
storage.Create<query::StartStopStream>((stream_name), false, nullptr)
|
|
|
|
#define START_ALL_STREAMS storage.Create<query::StartStopAllStreams>(true)
|
|
|
|
#define STOP_ALL_STREAMS storage.Create<query::StartStopAllStreams>(false)
|
2018-07-03 19:57:53 +08:00
|
|
|
#define TEST_STREAM(stream_name, limit_batches) \
|
|
|
|
storage.Create<query::TestStream>((stream_name), (limit_batches))
|