03c78c1277
Summary: - The new BFS syntax implemented as proposed. - AST BreadthFirstAtom now uses EdgeAtom members: has_range_{true}, upper_bound_, lower_bound_ - Edges data structure now handles all the edge filtering (single or multiple edges), to ease planning. Additional edge filtering (additional Filter op in the plan) is removed. AST EdgeTypeTest is no longer used and is removed. Current state is stable but there are things left to do: - BFS property filtering. - BFS lower_bound_ support. - Support for lambdas in variable length expansion. This includes obligatory (even if not user_defined) inner_node and inner_edge symbols for easier handling. - Code-sharing between BFS and variable length expansions. I'll add asana tasks (and probably start working on them immediately) when/if this lands. Reviewers: buda, teon.banek, mislav.bradac Reviewed By: teon.banek Subscribers: pullbot Differential Revision: https://phabricator.memgraph.io/D836
79 lines
2.6 KiB
C++
79 lines
2.6 KiB
C++
// tests in this suite deal with edge cases in logical operator behavior
|
|
// that's not easily testable with single-phase testing. instead, for
|
|
// easy testing and latter readability they are tested end-to-end.
|
|
|
|
#include "gmock/gmock.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
#include "communication/result_stream_faker.hpp"
|
|
#include "database/dbms.hpp"
|
|
#include "query/interpreter.hpp"
|
|
|
|
class QueryExecution : public testing::Test {
|
|
protected:
|
|
Dbms dbms_;
|
|
std::unique_ptr<GraphDbAccessor> db_ = dbms_.active();
|
|
|
|
/** Commits the current transaction and refreshes the db_
|
|
* variable to hold a new accessor with a new transaction */
|
|
void Commit() {
|
|
db_->Commit();
|
|
auto next_db = dbms_.active();
|
|
db_.swap(next_db);
|
|
}
|
|
|
|
/** Executes the query and returns the results.
|
|
* Does NOT commit the transaction */
|
|
auto Execute(const std::string &query) {
|
|
ResultStreamFaker results;
|
|
query::Interpreter().Interpret(query, *db_, results, {});
|
|
return results.GetResults();
|
|
}
|
|
};
|
|
|
|
TEST_F(QueryExecution, MissingOptionalIntoExpand) {
|
|
// validating bug where expanding from Null (due to a preceeding optional
|
|
// match) exhausts the expansion cursor, even if it's input is still not
|
|
// exhausted
|
|
Execute(
|
|
"CREATE (a:Person {id: 1}), (b:Person "
|
|
"{id:2})-[:Has]->(:Dog)-[:Likes]->(:Food )");
|
|
Commit();
|
|
ASSERT_EQ(Execute("MATCH (n) RETURN n").size(), 4);
|
|
|
|
auto Exec = [this](bool desc, const std::string &edge_pattern) {
|
|
// this test depends on left-to-right query planning
|
|
FLAGS_query_cost_planner = false;
|
|
return Execute(std::string("MATCH (p:Person) WITH p ORDER BY p.id ") +
|
|
(desc ? "DESC " : "") +
|
|
"OPTIONAL MATCH (p)-->(d:Dog) WITH p, d "
|
|
"MATCH (d)" + edge_pattern +
|
|
"(f:Food) "
|
|
"RETURN p, d, f")
|
|
.size();
|
|
};
|
|
|
|
std::string expand = "-->";
|
|
std::string variable = "-[*1]->";
|
|
std::string bfs = "-[*bfs..1]->";
|
|
|
|
EXPECT_EQ(Exec(false, expand), 1);
|
|
EXPECT_EQ(Exec(true, expand), 1);
|
|
EXPECT_EQ(Exec(false, variable), 1);
|
|
EXPECT_EQ(Exec(true, bfs), 1);
|
|
EXPECT_EQ(Exec(true, bfs), 1);
|
|
}
|
|
|
|
TEST_F(QueryExecution, EdgeUniquenessInOptional) {
|
|
// Validating that an edge uniqueness check can't fail when the edge is Null
|
|
// due to optonal match. Since edge-uniqueness only happens in one OPTIONAL
|
|
// MATCH, we only need to check that scenario.
|
|
Execute("CREATE (), ()-[:Type]->()");
|
|
Commit();
|
|
ASSERT_EQ(Execute("MATCH (n) RETURN n").size(), 3);
|
|
EXPECT_EQ(Execute("MATCH (n) OPTIONAL MATCH (n)-[r1]->(), (n)-[r2]->() "
|
|
"RETURN n, r1, r2")
|
|
.size(),
|
|
3);
|
|
}
|