Remove output formatters from vertex/edge accessors
Reviewers: teon.banek Reviewed By: teon.banek Subscribers: pullbot Differential Revision: https://phabricator.memgraph.io/D2555
This commit is contained in:
parent
d5f02c5ef8
commit
8be2b4af63
@ -70,10 +70,6 @@ class EdgeAccessor final {
|
||||
bool operator==(const EdgeAccessor &e) const { return impl_ == e.impl_; }
|
||||
|
||||
bool operator!=(const EdgeAccessor &e) const { return !(*this == e); }
|
||||
|
||||
friend std::ostream &operator<<(std::ostream &s, const EdgeAccessor &e) {
|
||||
throw utils::NotYetImplemented("operator<<");
|
||||
}
|
||||
};
|
||||
|
||||
class VertexAccessor final {
|
||||
@ -178,10 +174,6 @@ class VertexAccessor final {
|
||||
bool operator==(const VertexAccessor &v) const { return impl_ == v.impl_; }
|
||||
|
||||
bool operator!=(const VertexAccessor &v) const { return !(*this == v); }
|
||||
|
||||
friend std::ostream &operator<<(std::ostream &s, const VertexAccessor &v) {
|
||||
throw utils::NotYetImplemented("operator<<");
|
||||
}
|
||||
};
|
||||
|
||||
inline VertexAccessor EdgeAccessor::To() const {
|
||||
@ -285,10 +277,6 @@ class EdgeAccessor final {
|
||||
bool operator==(const EdgeAccessor &e) const { return impl_ == e.impl_; }
|
||||
|
||||
bool operator!=(const EdgeAccessor &e) const { return !(*this == e); }
|
||||
|
||||
friend std::ostream &operator<<(std::ostream &s, const EdgeAccessor &e) {
|
||||
return s << e.impl_;
|
||||
}
|
||||
};
|
||||
|
||||
class VertexAccessor final {
|
||||
@ -471,10 +459,6 @@ class VertexAccessor final {
|
||||
bool operator==(const VertexAccessor &v) const { return impl_ == v.impl_; }
|
||||
|
||||
bool operator!=(const VertexAccessor &v) const { return !(*this == v); }
|
||||
|
||||
friend std::ostream &operator<<(std::ostream &s, const VertexAccessor &v) {
|
||||
return s << v.impl_;
|
||||
}
|
||||
};
|
||||
|
||||
inline VertexAccessor EdgeAccessor::To() const {
|
||||
|
@ -138,21 +138,6 @@ class Path {
|
||||
return vertices_ == other.vertices_ && edges_ == other.edges_;
|
||||
}
|
||||
|
||||
friend std::ostream &operator<<(std::ostream &os, const Path &path) {
|
||||
DCHECK(path.vertices_.size() > 0U)
|
||||
<< "Attempting to stream out an invalid path";
|
||||
os << path.vertices_[0];
|
||||
for (int i = 0; i < static_cast<int>(path.edges_.size()); i++) {
|
||||
bool arrow_to_left = path.vertices_[i] == path.edges_[i].To();
|
||||
if (arrow_to_left) os << "<";
|
||||
os << "-" << path.edges_[i] << "-";
|
||||
if (!arrow_to_left) os << ">";
|
||||
os << path.vertices_[i + 1];
|
||||
}
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
private:
|
||||
// Contains all the vertices in the path.
|
||||
utils::pmr::vector<VertexAccessor> vertices_;
|
||||
|
@ -9,7 +9,6 @@
|
||||
|
||||
#include "glog/logging.h"
|
||||
|
||||
#include "utils/algorithm.hpp"
|
||||
#include "utils/exceptions.hpp"
|
||||
#include "utils/hashing/fnv.hpp"
|
||||
|
||||
@ -288,39 +287,6 @@ std::ostream &operator<<(std::ostream &os, const TypedValue::Type &type) {
|
||||
LOG(FATAL) << "Unsupported TypedValue::Type";
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, const TypedValue &value) {
|
||||
switch (value.type()) {
|
||||
case TypedValue::Type::Null:
|
||||
return os << "Null";
|
||||
case TypedValue::Type::Bool:
|
||||
return os << (value.ValueBool() ? "true" : "false");
|
||||
case TypedValue::Type::Int:
|
||||
return os << value.ValueInt();
|
||||
case TypedValue::Type::Double:
|
||||
return os << value.ValueDouble();
|
||||
case TypedValue::Type::String:
|
||||
return os << value.ValueString();
|
||||
case TypedValue::Type::List:
|
||||
os << "[";
|
||||
utils::PrintIterable(os, value.ValueList());
|
||||
return os << "]";
|
||||
case TypedValue::Type::Map:
|
||||
os << "{";
|
||||
utils::PrintIterable(os, value.ValueMap(), ", ",
|
||||
[](auto &stream, const auto &pair) {
|
||||
stream << pair.first << ": " << pair.second;
|
||||
});
|
||||
return os << "}";
|
||||
case TypedValue::Type::Vertex:
|
||||
return os << value.ValueVertex();
|
||||
case TypedValue::Type::Edge:
|
||||
return os << value.ValueEdge();
|
||||
case TypedValue::Type::Path:
|
||||
return os << value.ValuePath();
|
||||
}
|
||||
LOG(FATAL) << "Unsupported PropertyValue::Type";
|
||||
}
|
||||
|
||||
#define DEFINE_TYPED_VALUE_COPY_ASSIGNMENT(type_param, typed_value_type, \
|
||||
member) \
|
||||
TypedValue &TypedValue::operator=(type_param other) { \
|
||||
|
@ -733,11 +733,4 @@ TypedValue operator%(const TypedValue &a, const TypedValue &b);
|
||||
/** Output the TypedValue::Type value as a string */
|
||||
std::ostream &operator<<(std::ostream &os, const TypedValue::Type &type);
|
||||
|
||||
/**
|
||||
* Output the TypedValue value as a readable string.
|
||||
* Note that the primary use of this is for debugging and may not yield the
|
||||
* pretty results you want to display to the user.
|
||||
*/
|
||||
std::ostream &operator<<(std::ostream &os, const TypedValue &value);
|
||||
|
||||
} // namespace query
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "query/plan/planner.hpp"
|
||||
#include "query/plan/pretty_print.hpp"
|
||||
#include "query/typed_value.hpp"
|
||||
#include "storage/v2/property_value.hpp"
|
||||
#include "utils/string.hpp"
|
||||
|
||||
DEFINE_string(save_mock_db_file, "",
|
||||
@ -168,15 +169,14 @@ class InteractiveDbAccessor {
|
||||
return 0;
|
||||
}
|
||||
auto &value_vertex_count = property_value_vertex_count_[label_prop];
|
||||
query::TypedValue tv_value(value);
|
||||
if (value_vertex_count.find(tv_value) == value_vertex_count.end()) {
|
||||
if (value_vertex_count.find(value) == value_vertex_count.end()) {
|
||||
std::stringstream ss;
|
||||
ss << tv_value;
|
||||
ss << value;
|
||||
int64_t count = ReadVertexCount("label '" + label + "' and property '" +
|
||||
property + "' value '" + ss.str() + "'");
|
||||
value_vertex_count[tv_value] = count;
|
||||
value_vertex_count[value] = count;
|
||||
}
|
||||
return value_vertex_count.at(tv_value);
|
||||
return value_vertex_count.at(value);
|
||||
}
|
||||
|
||||
int64_t VerticesCount(
|
||||
@ -301,7 +301,7 @@ class InteractiveDbAccessor {
|
||||
}
|
||||
DLOG(INFO) << "Load " << label << " " << property << " " << value_count;
|
||||
for (int v = 0; v < value_count; ++v) {
|
||||
auto value = LoadTypedValue(in);
|
||||
auto value = LoadPropertyValue(in);
|
||||
int64_t count;
|
||||
in >> count;
|
||||
if (in.fail()) {
|
||||
@ -324,10 +324,8 @@ class InteractiveDbAccessor {
|
||||
std::map<std::pair<std::string, std::string>, int64_t>
|
||||
label_property_vertex_count_;
|
||||
std::map<std::pair<std::string, std::string>, bool> label_property_index_;
|
||||
std::map<
|
||||
std::pair<std::string, std::string>,
|
||||
std::unordered_map<query::TypedValue, int64_t, query::TypedValue::Hash,
|
||||
query::TypedValue::BoolEqual>>
|
||||
std::map<std::pair<std::string, std::string>,
|
||||
std::map<storage::PropertyValue, int64_t>>
|
||||
property_value_vertex_count_;
|
||||
// TODO: Cache faked index counts by range.
|
||||
|
||||
@ -336,27 +334,27 @@ class InteractiveDbAccessor {
|
||||
[&message]() { return ReadInt("Vertices with " + message + ": "); });
|
||||
}
|
||||
|
||||
query::TypedValue LoadTypedValue(std::istream &in) {
|
||||
storage::PropertyValue LoadPropertyValue(std::istream &in) {
|
||||
std::string type;
|
||||
in >> type;
|
||||
if (type == "bool") {
|
||||
return LoadTypedValue<bool>(in);
|
||||
return LoadPropertyValue<bool>(in);
|
||||
} else if (type == "int") {
|
||||
return LoadTypedValue<int64_t>(in);
|
||||
return LoadPropertyValue<int64_t>(in);
|
||||
} else if (type == "double") {
|
||||
return LoadTypedValue<double>(in);
|
||||
return LoadPropertyValue<double>(in);
|
||||
} else if (type == "string") {
|
||||
return LoadTypedValue<std::string>(in);
|
||||
return LoadPropertyValue<std::string>(in);
|
||||
} else {
|
||||
throw utils::BasicException("Unable to read type '{}'", type);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
query::TypedValue LoadTypedValue(std::istream &in) {
|
||||
storage::PropertyValue LoadPropertyValue(std::istream &in) {
|
||||
T val;
|
||||
in >> val;
|
||||
return query::TypedValue(val);
|
||||
return storage::PropertyValue(val);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -8,6 +8,8 @@
|
||||
#include "query/plan/operator.hpp"
|
||||
#include "query_common.hpp"
|
||||
|
||||
#include "formatters.hpp"
|
||||
|
||||
namespace query {
|
||||
void PrintTo(const query::EdgeAtom::Direction &dir, std::ostream *os) {
|
||||
switch (dir) {
|
||||
@ -436,7 +438,8 @@ void BfsTest(Database *db, int lower_bound, int upper_bound,
|
||||
query::TypedValue::BoolEqual{}(results[j][3], blocked))
|
||||
++j;
|
||||
|
||||
SCOPED_TRACE(fmt::format("blocked entity = {}", blocked));
|
||||
SCOPED_TRACE(
|
||||
fmt::format("blocked entity = {}", ToString(blocked, execution_dba)));
|
||||
|
||||
// When an edge is blocked, it is blocked in both directions so we remove
|
||||
// it before modifying edge list to account for direction and edge types;
|
||||
|
119
tests/unit/formatters.hpp
Normal file
119
tests/unit/formatters.hpp
Normal file
@ -0,0 +1,119 @@
|
||||
#pragma once
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include <glog/logging.h>
|
||||
|
||||
#include "query/typed_value.hpp"
|
||||
#include "utils/algorithm.hpp"
|
||||
|
||||
/// Functions that convert types to a `std::string` representation of it. The
|
||||
/// `TAccessor` supplied must have the functions `NameToLabel`, `LabelToName`,
|
||||
/// `NameToProperty`, `PropertyToName`, `NameToEdgeType` and `EdgeTypeToName`.
|
||||
/// For example, both `storage::Storage` and `storage::Storage::Accessor` will
|
||||
/// be apropriate.
|
||||
|
||||
template <class TAccessor>
|
||||
inline std::string ToString(const query::VertexAccessor &vertex,
|
||||
const TAccessor &acc) {
|
||||
std::ostringstream os;
|
||||
os << "V(";
|
||||
auto maybe_labels = vertex.Labels(storage::View::NEW);
|
||||
CHECK(maybe_labels.HasValue());
|
||||
utils::PrintIterable(os, *maybe_labels, ":", [&](auto &stream, auto label) {
|
||||
stream << acc.LabelToName(label);
|
||||
});
|
||||
if (maybe_labels->size() > 0) os << " ";
|
||||
os << "{";
|
||||
auto maybe_properties = vertex.Properties(storage::View::NEW);
|
||||
CHECK(maybe_properties.HasValue());
|
||||
utils::PrintIterable(
|
||||
os, *maybe_properties, ", ", [&](auto &stream, const auto &pair) {
|
||||
stream << acc.PropertyToName(pair.first) << ": " << pair.second;
|
||||
});
|
||||
os << "})";
|
||||
return os.str();
|
||||
}
|
||||
|
||||
template <class TAccessor>
|
||||
inline std::string ToString(const query::EdgeAccessor &edge,
|
||||
const TAccessor &acc) {
|
||||
std::ostringstream os;
|
||||
os << "E[" << acc.EdgeTypeToName(edge.EdgeType());
|
||||
os << " {";
|
||||
auto maybe_properties = edge.Properties(storage::View::NEW);
|
||||
CHECK(maybe_properties.HasValue());
|
||||
utils::PrintIterable(
|
||||
os, *maybe_properties, ", ", [&](auto &stream, const auto &pair) {
|
||||
stream << acc.PropertyToName(pair.first) << ": " << pair.second;
|
||||
});
|
||||
os << "}]";
|
||||
return os.str();
|
||||
}
|
||||
|
||||
template <class TAccessor>
|
||||
inline std::string ToString(const query::Path &path, const TAccessor &acc) {
|
||||
std::ostringstream os;
|
||||
const auto &vertices = path.vertices();
|
||||
const auto &edges = path.edges();
|
||||
CHECK(vertices.size() > 0U) << "Attempting to stream out an invalid path";
|
||||
os << ToString(vertices[0], acc);
|
||||
for (size_t i = 0; i < edges.size(); ++i) {
|
||||
bool arrow_to_left = vertices[i] == edges[i].To();
|
||||
if (arrow_to_left) os << "<";
|
||||
os << "-" << ToString(edges[i], acc) << "-";
|
||||
if (!arrow_to_left) os << ">";
|
||||
os << ToString(vertices[i + 1], acc);
|
||||
}
|
||||
return os.str();
|
||||
}
|
||||
|
||||
template <class TAccessor>
|
||||
inline std::string ToString(const query::TypedValue &value,
|
||||
const TAccessor &acc) {
|
||||
std::ostringstream os;
|
||||
switch (value.type()) {
|
||||
case query::TypedValue::Type::Null:
|
||||
os << "null";
|
||||
break;
|
||||
case query::TypedValue::Type::Bool:
|
||||
os << (value.ValueBool() ? "true" : "false");
|
||||
break;
|
||||
case query::TypedValue::Type::Int:
|
||||
os << value.ValueInt();
|
||||
break;
|
||||
case query::TypedValue::Type::Double:
|
||||
os << value.ValueDouble();
|
||||
break;
|
||||
case query::TypedValue::Type::String:
|
||||
os << value.ValueString();
|
||||
break;
|
||||
case query::TypedValue::Type::List:
|
||||
os << "[";
|
||||
utils::PrintIterable(os, value.ValueList(), ", ",
|
||||
[&](auto &stream, const auto &item) {
|
||||
stream << ToString(item, acc);
|
||||
});
|
||||
os << "]";
|
||||
break;
|
||||
case query::TypedValue::Type::Map:
|
||||
os << "{";
|
||||
utils::PrintIterable(
|
||||
os, value.ValueMap(), ", ", [&](auto &stream, const auto &pair) {
|
||||
stream << pair.first << ": " << ToString(pair.second, acc);
|
||||
});
|
||||
os << "}";
|
||||
break;
|
||||
case query::TypedValue::Type::Vertex:
|
||||
os << ToString(value.ValueVertex(), acc);
|
||||
break;
|
||||
case query::TypedValue::Type::Edge:
|
||||
os << ToString(value.ValueEdge(), acc);
|
||||
break;
|
||||
case query::TypedValue::Type::Path:
|
||||
os << ToString(value.ValuePath(), acc);
|
||||
break;
|
||||
}
|
||||
return os.str();
|
||||
}
|
@ -9,31 +9,38 @@
|
||||
|
||||
#include "query_plan_common.hpp"
|
||||
|
||||
#include "formatters.hpp"
|
||||
|
||||
using namespace query::plan;
|
||||
using query::AstStorage;
|
||||
using Type = query::EdgeAtom::Type;
|
||||
using Direction = query::EdgeAtom::Direction;
|
||||
|
||||
namespace std {
|
||||
|
||||
// Overloads for printing resulting rows from a query.
|
||||
std::ostream &operator<<(std::ostream &stream,
|
||||
const std::vector<TypedValue> &row) {
|
||||
utils::PrintIterable(stream, row);
|
||||
return stream;
|
||||
// Functions for printing resulting rows from a query.
|
||||
template <class TAccessor>
|
||||
std::string ToString(const std::vector<TypedValue> &row, const TAccessor &acc) {
|
||||
std::ostringstream os;
|
||||
utils::PrintIterable(os, row, ", ", [&](auto &stream, const auto &item) {
|
||||
stream << ToString(item, acc);
|
||||
});
|
||||
return os.str();
|
||||
}
|
||||
std::ostream &operator<<(std::ostream &stream,
|
||||
const std::vector<std::vector<TypedValue>> &rows) {
|
||||
utils::PrintIterable(stream, rows, "\n");
|
||||
return stream;
|
||||
template <class TAccessor>
|
||||
std::string ToString(const std::vector<std::vector<TypedValue>> &rows,
|
||||
const TAccessor &acc) {
|
||||
std::ostringstream os;
|
||||
utils::PrintIterable(os, rows, "\n", [&](auto &stream, const auto &item) {
|
||||
stream << ToString(item, acc);
|
||||
});
|
||||
return os.str();
|
||||
}
|
||||
|
||||
} // namespace std
|
||||
|
||||
namespace {
|
||||
|
||||
template <class TAccessor>
|
||||
void AssertRows(const std::vector<std::vector<TypedValue>> &datum,
|
||||
std::vector<std::vector<TypedValue>> expected) {
|
||||
std::vector<std::vector<TypedValue>> expected,
|
||||
const TAccessor &acc) {
|
||||
auto row_equal = [](const auto &row1, const auto &row2) {
|
||||
if (row1.size() != row2.size()) {
|
||||
return false;
|
||||
@ -51,19 +58,18 @@ void AssertRows(const std::vector<std::vector<TypedValue>> &datum,
|
||||
ASSERT_TRUE(std::is_permutation(datum.begin(), datum.end(), expected.begin(),
|
||||
expected.end(), row_equal))
|
||||
<< "Actual rows:" << std::endl
|
||||
<< datum << std::endl
|
||||
<< ToString(datum, acc) << std::endl
|
||||
<< "Expected rows:" << std::endl
|
||||
<< expected;
|
||||
<< ToString(expected, acc);
|
||||
};
|
||||
|
||||
void CheckPlansProduce(
|
||||
size_t expected_plan_count, query::CypherQuery *query, AstStorage &storage,
|
||||
database::GraphDbAccessor *dba,
|
||||
query::DbAccessor *dba,
|
||||
std::function<void(const std::vector<std::vector<TypedValue>> &)> check) {
|
||||
auto symbol_table = query::MakeSymbolTable(query);
|
||||
query::DbAccessor execution_dba(dba);
|
||||
auto planning_context =
|
||||
MakePlanningContext(&storage, &symbol_table, query, &execution_dba);
|
||||
MakePlanningContext(&storage, &symbol_table, query, dba);
|
||||
auto query_parts = CollectQueryParts(symbol_table, storage, query);
|
||||
EXPECT_TRUE(query_parts.query_parts.size() > 0);
|
||||
auto single_query_parts = query_parts.query_parts.at(0).single_query_parts;
|
||||
@ -73,7 +79,7 @@ void CheckPlansProduce(
|
||||
for (const auto &plan : plans) {
|
||||
auto *produce = dynamic_cast<Produce *>(plan.get());
|
||||
ASSERT_TRUE(produce);
|
||||
auto context = MakeContext(storage, symbol_table, &execution_dba);
|
||||
auto context = MakeContext(storage, symbol_table, dba);
|
||||
auto results = CollectProduce(*produce, &context);
|
||||
check(results);
|
||||
}
|
||||
@ -93,10 +99,13 @@ TEST(TestVariableStartPlanner, MatchReturn) {
|
||||
MATCH(PATTERN(NODE("n"), EDGE("r", Direction::OUT), NODE("m"))),
|
||||
RETURN("n")));
|
||||
// We have 2 nodes `n` and `m` from which we could start, so expect 2 plans.
|
||||
CheckPlansProduce(2, query, storage, &dba, [&](const auto &results) {
|
||||
// We expect to produce only a single (v1) node.
|
||||
AssertRows(results, {{TypedValue(query::VertexAccessor(v1))}});
|
||||
});
|
||||
query::DbAccessor execution_dba(&dba);
|
||||
CheckPlansProduce(
|
||||
2, query, storage, &execution_dba, [&](const auto &results) {
|
||||
// We expect to produce only a single (v1) node.
|
||||
AssertRows(results, {{TypedValue(query::VertexAccessor(v1))}},
|
||||
execution_dba);
|
||||
});
|
||||
}
|
||||
|
||||
TEST(TestVariableStartPlanner, MatchTripletPatternReturn) {
|
||||
@ -117,10 +126,13 @@ TEST(TestVariableStartPlanner, MatchTripletPatternReturn) {
|
||||
EDGE("e", Direction::OUT), NODE("l"))),
|
||||
RETURN("n")));
|
||||
// We have 3 nodes: `n`, `m` and `l` from which we could start.
|
||||
CheckPlansProduce(3, query, storage, &dba, [&](const auto &results) {
|
||||
// We expect to produce only a single (v1) node.
|
||||
AssertRows(results, {{TypedValue(query::VertexAccessor(v1))}});
|
||||
});
|
||||
query::DbAccessor execution_dba(&dba);
|
||||
CheckPlansProduce(
|
||||
3, query, storage, &execution_dba, [&](const auto &results) {
|
||||
// We expect to produce only a single (v1) node.
|
||||
AssertRows(results, {{TypedValue(query::VertexAccessor(v1))}},
|
||||
execution_dba);
|
||||
});
|
||||
}
|
||||
{
|
||||
// Equivalent to `MATCH (n) -[r]-> (m), (m) -[e]-> (l) RETURN n`.
|
||||
@ -129,9 +141,12 @@ TEST(TestVariableStartPlanner, MatchTripletPatternReturn) {
|
||||
MATCH(PATTERN(NODE("n"), EDGE("r", Direction::OUT), NODE("m")),
|
||||
PATTERN(NODE("m"), EDGE("e", Direction::OUT), NODE("l"))),
|
||||
RETURN("n")));
|
||||
CheckPlansProduce(3, query, storage, &dba, [&](const auto &results) {
|
||||
AssertRows(results, {{TypedValue(query::VertexAccessor(v1))}});
|
||||
});
|
||||
query::DbAccessor execution_dba(&dba);
|
||||
CheckPlansProduce(
|
||||
3, query, storage, &execution_dba, [&](const auto &results) {
|
||||
AssertRows(results, {{TypedValue(query::VertexAccessor(v1))}},
|
||||
execution_dba);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -153,15 +168,18 @@ TEST(TestVariableStartPlanner, MatchOptionalMatchReturn) {
|
||||
RETURN("n", "l")));
|
||||
// We have 2 nodes `n` and `m` from which we could start the MATCH, and 2
|
||||
// nodes for OPTIONAL MATCH. This should produce 2 * 2 plans.
|
||||
CheckPlansProduce(4, query, storage, &dba, [&](const auto &results) {
|
||||
// We expect to produce 2 rows:
|
||||
// * (v1), (v3)
|
||||
// * (v2), null
|
||||
AssertRows(results,
|
||||
{{TypedValue(query::VertexAccessor(v1)),
|
||||
TypedValue(query::VertexAccessor(v3))},
|
||||
{TypedValue(query::VertexAccessor(v2)), TypedValue()}});
|
||||
});
|
||||
query::DbAccessor execution_dba(&dba);
|
||||
CheckPlansProduce(
|
||||
4, query, storage, &execution_dba, [&](const auto &results) {
|
||||
// We expect to produce 2 rows:
|
||||
// * (v1), (v3)
|
||||
// * (v2), null
|
||||
AssertRows(results,
|
||||
{{TypedValue(query::VertexAccessor(v1)),
|
||||
TypedValue(query::VertexAccessor(v3))},
|
||||
{TypedValue(query::VertexAccessor(v2)), TypedValue()}},
|
||||
execution_dba);
|
||||
});
|
||||
}
|
||||
|
||||
TEST(TestVariableStartPlanner, MatchOptionalMatchMergeReturn) {
|
||||
@ -185,11 +203,15 @@ TEST(TestVariableStartPlanner, MatchOptionalMatchMergeReturn) {
|
||||
RETURN("n", "m", "l", "u", "v")));
|
||||
// Since MATCH, OPTIONAL MATCH and MERGE each have 2 nodes from which we can
|
||||
// start, we generate 2 * 2 * 2 plans.
|
||||
CheckPlansProduce(8, query, storage, &dba, [&](const auto &results) {
|
||||
// We expect to produce a single row: (v1), (v2), null, (v1), (v2)
|
||||
AssertRows(results, {{TypedValue(v1), TypedValue(v2), TypedValue(),
|
||||
TypedValue(v1), TypedValue(v2)}});
|
||||
});
|
||||
query::DbAccessor execution_dba(&dba);
|
||||
CheckPlansProduce(8, query, storage, &execution_dba,
|
||||
[&](const auto &results) {
|
||||
// We expect to produce a single row: (v1), (v2), null, (v1), (v2)
|
||||
AssertRows(results,
|
||||
{{TypedValue(v1), TypedValue(v2), TypedValue(),
|
||||
TypedValue(v1), TypedValue(v2)}},
|
||||
execution_dba);
|
||||
});
|
||||
}
|
||||
|
||||
TEST(TestVariableStartPlanner, MatchWithMatchReturn) {
|
||||
@ -209,10 +231,13 @@ TEST(TestVariableStartPlanner, MatchWithMatchReturn) {
|
||||
RETURN("n", "m", "l")));
|
||||
// We can start from 2 nodes in each match. Since WITH separates query parts,
|
||||
// we expect to get 2 plans for each, which totals 2 * 2.
|
||||
CheckPlansProduce(4, query, storage, &dba, [&](const auto &results) {
|
||||
// We expect to produce a single row: (v1), (v1), (v2)
|
||||
AssertRows(results, {{TypedValue(v1), TypedValue(v1), TypedValue(v2)}});
|
||||
});
|
||||
query::DbAccessor execution_dba(&dba);
|
||||
CheckPlansProduce(
|
||||
4, query, storage, &execution_dba, [&](const auto &results) {
|
||||
// We expect to produce a single row: (v1), (v1), (v2)
|
||||
AssertRows(results, {{TypedValue(v1), TypedValue(v1), TypedValue(v2)}},
|
||||
execution_dba);
|
||||
});
|
||||
}
|
||||
|
||||
TEST(TestVariableStartPlanner, MatchVariableExpand) {
|
||||
@ -236,9 +261,12 @@ TEST(TestVariableStartPlanner, MatchVariableExpand) {
|
||||
// [r1, r2]
|
||||
TypedValue r1_r2_list(
|
||||
std::vector<TypedValue>{TypedValue(r1), TypedValue(r2)});
|
||||
CheckPlansProduce(2, query, storage, &dba, [&](const auto &results) {
|
||||
AssertRows(results, {{r1_list}, {r2_list}, {r1_r2_list}});
|
||||
});
|
||||
query::DbAccessor execution_dba(&dba);
|
||||
CheckPlansProduce(2, query, storage, &execution_dba,
|
||||
[&](const auto &results) {
|
||||
AssertRows(results, {{r1_list}, {r2_list}, {r1_r2_list}},
|
||||
execution_dba);
|
||||
});
|
||||
}
|
||||
|
||||
TEST(TestVariableStartPlanner, MatchVariableExpandReferenceNode) {
|
||||
@ -266,9 +294,11 @@ TEST(TestVariableStartPlanner, MatchVariableExpandReferenceNode) {
|
||||
TypedValue r1_list(std::vector<TypedValue>{TypedValue(r1)});
|
||||
// [r2] (v2 -[*..2]-> v3)
|
||||
TypedValue r2_list(std::vector<TypedValue>{TypedValue(r2)});
|
||||
CheckPlansProduce(2, query, storage, &dba, [&](const auto &results) {
|
||||
AssertRows(results, {{r1_list}, {r2_list}});
|
||||
});
|
||||
query::DbAccessor execution_dba(&dba);
|
||||
CheckPlansProduce(
|
||||
2, query, storage, &execution_dba, [&](const auto &results) {
|
||||
AssertRows(results, {{r1_list}, {r2_list}}, execution_dba);
|
||||
});
|
||||
}
|
||||
|
||||
TEST(TestVariableStartPlanner, MatchVariableExpandBoth) {
|
||||
@ -295,9 +325,11 @@ TEST(TestVariableStartPlanner, MatchVariableExpandBoth) {
|
||||
// [r1, r2]
|
||||
TypedValue r1_r2_list(
|
||||
std::vector<TypedValue>{TypedValue(r1), TypedValue(r2)});
|
||||
CheckPlansProduce(2, query, storage, &dba, [&](const auto &results) {
|
||||
AssertRows(results, {{r1_list}, {r1_r2_list}});
|
||||
});
|
||||
query::DbAccessor execution_dba(&dba);
|
||||
CheckPlansProduce(
|
||||
2, query, storage, &execution_dba, [&](const auto &results) {
|
||||
AssertRows(results, {{r1_list}, {r1_r2_list}}, execution_dba);
|
||||
});
|
||||
}
|
||||
|
||||
TEST(TestVariableStartPlanner, MatchBfs) {
|
||||
@ -327,9 +359,11 @@ TEST(TestVariableStartPlanner, MatchBfs) {
|
||||
SINGLE_QUERY(MATCH(PATTERN(NODE("n"), bfs, NODE("m"))), RETURN("r")));
|
||||
// We expect to get a single column with the following rows:
|
||||
TypedValue r1_list(std::vector<TypedValue>{TypedValue(r1)}); // [r1]
|
||||
CheckPlansProduce(2, query, storage, &dba, [&](const auto &results) {
|
||||
AssertRows(results, {{r1_list}});
|
||||
});
|
||||
query::DbAccessor execution_dba(&dba);
|
||||
CheckPlansProduce(2, query, storage, &execution_dba,
|
||||
[&](const auto &results) {
|
||||
AssertRows(results, {{r1_list}}, execution_dba);
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
Loading…
Reference in New Issue
Block a user