Remove Dbms
Summary: Remove name from GraphDb. Take GraphDb in query test macros instead of accessor. Add is_accepting_transactions flag to GraphDb. Reviewers: mislav.bradac, florijan, mferencevic Reviewed By: mislav.bradac Subscribers: mferencevic, pullbot Differential Revision: https://phabricator.memgraph.io/D940
This commit is contained in:
parent
7ab6da5f6a
commit
55456b4214
@ -190,7 +190,6 @@ set(memgraph_src_files
|
||||
${src_dir}/communication/reactor/reactor_local.cpp
|
||||
${src_dir}/communication/reactor/reactor_distributed.cpp
|
||||
${src_dir}/data_structures/concurrent/skiplist_gc.cpp
|
||||
${src_dir}/database/dbms.cpp
|
||||
${src_dir}/database/graph_db.cpp
|
||||
${src_dir}/database/graph_db_accessor.cpp
|
||||
${src_dir}/durability/recovery.cpp
|
||||
|
@ -6,7 +6,6 @@
|
||||
#include "io/network/socket.hpp"
|
||||
#include "io/network/stream_buffer.hpp"
|
||||
|
||||
#include "database/dbms.hpp"
|
||||
#include "query/interpreter.hpp"
|
||||
#include "transactions/transaction.hpp"
|
||||
|
||||
@ -32,7 +31,7 @@ namespace communication::bolt {
|
||||
* that are passed through the network server and worker to the session.
|
||||
*/
|
||||
struct SessionData {
|
||||
Dbms dbms;
|
||||
GraphDb db;
|
||||
query::Interpreter interpreter;
|
||||
};
|
||||
|
||||
@ -67,7 +66,7 @@ class Session {
|
||||
|
||||
Session(TSocket &&socket, SessionData &data)
|
||||
: socket_(std::move(socket)),
|
||||
dbms_(data.dbms),
|
||||
db_(data.db),
|
||||
interpreter_(data.interpreter) {}
|
||||
|
||||
~Session() {
|
||||
@ -203,7 +202,7 @@ class Session {
|
||||
// TODO: Rethink if there is a way to hide some members. At the momement all
|
||||
// of them are public.
|
||||
TSocket socket_;
|
||||
Dbms &dbms_;
|
||||
GraphDb &db_;
|
||||
query::Interpreter &interpreter_;
|
||||
|
||||
TimeoutSocket timeout_socket_{*this};
|
||||
|
@ -72,17 +72,18 @@ State HandleRun(TSession &session, State state, Marker marker) {
|
||||
// Transaction already exists.
|
||||
in_explicit_transaction = true;
|
||||
} else {
|
||||
// Create new transaction.
|
||||
session.db_accessor_ = session.dbms_.active();
|
||||
if (!session.db_accessor_) {
|
||||
// Dbms is shutting down and doesn't accept new transactions so we should
|
||||
// TODO: Possible (but very unlikely) race condition, where we have alive
|
||||
// session during shutdown, but is_accepting_transactions_ isn't yet false.
|
||||
// We should probably create transactions under some locking mechanism.
|
||||
if (!session.db_.is_accepting_transactions_) {
|
||||
// Db is shutting down and doesn't accept new transactions so we should
|
||||
// close this session.
|
||||
return State::Close;
|
||||
}
|
||||
// Create new transaction.
|
||||
session.db_accessor_ = std::make_unique<GraphDbAccessor>(session.db_);
|
||||
}
|
||||
|
||||
DLOG(INFO) << fmt::format("[ActiveDB] '{}'", session.db_accessor_->name());
|
||||
|
||||
// If there was not explicitly started transaction before maybe we are
|
||||
// starting one now.
|
||||
if (!in_explicit_transaction && query.ValueString() == "BEGIN") {
|
||||
|
@ -1,30 +0,0 @@
|
||||
#include "gflags/gflags.h"
|
||||
|
||||
#include "database/dbms.hpp"
|
||||
|
||||
DEFINE_string(snapshot_directory, "snapshots",
|
||||
"Relative path to directory in which to save snapshots.");
|
||||
DEFINE_bool(snapshot_recover_on_startup, false, "Recover database on startup.");
|
||||
|
||||
std::unique_ptr<GraphDbAccessor> Dbms::active() {
|
||||
return std::make_unique<GraphDbAccessor>(
|
||||
*active_db.load(std::memory_order_acquire));
|
||||
}
|
||||
|
||||
std::unique_ptr<GraphDbAccessor> Dbms::active(const std::string &name,
|
||||
const fs::path &snapshot_db_dir) {
|
||||
if (!alive_) return nullptr;
|
||||
auto acc = dbs.access();
|
||||
// create db if it doesn't exist
|
||||
auto it = acc.find(name);
|
||||
if (it == acc.end()) {
|
||||
it = acc.emplace(name, std::forward_as_tuple(name),
|
||||
std::forward_as_tuple(name, snapshot_db_dir))
|
||||
.first;
|
||||
}
|
||||
|
||||
// set and return active db
|
||||
auto &db = it->second;
|
||||
active_db.store(&db);
|
||||
return std::make_unique<GraphDbAccessor>(db);
|
||||
}
|
@ -1,105 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "gflags/gflags.h"
|
||||
|
||||
#include "data_structures/concurrent/concurrent_map.hpp"
|
||||
#include "database/graph_db.hpp"
|
||||
#include "database/graph_db_accessor.hpp"
|
||||
#include "durability/recovery.hpp"
|
||||
#include "utils/exceptions.hpp"
|
||||
|
||||
DECLARE_string(snapshot_directory);
|
||||
DECLARE_bool(snapshot_recover_on_startup);
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
// Always be sure that Dbms object is destructed before main exits, i. e. Dbms
|
||||
// object shouldn't be part of global/static variable, except if its destructor
|
||||
// is explicitly called before main exits.
|
||||
// Consider code:
|
||||
//
|
||||
// Dbms dbms; // KeyIndex is created as a part of dbms.
|
||||
// int main() {
|
||||
// auto dba = dbms.active();
|
||||
// auto v = dba->InsertVertex();
|
||||
// v.add_label(dba->Label(
|
||||
// "Start")); // New SkipList is created in KeyIndex for LabelIndex.
|
||||
// // That SkipList creates SkipListGc which
|
||||
// // initialises static Executor object.
|
||||
// return 0;
|
||||
// }
|
||||
//
|
||||
// After main exits: 1. Executor is destructed, 2. KeyIndex is destructed.
|
||||
// Destructor of KeyIndex calls delete on created SkipLists which destroy
|
||||
// SkipListGc that tries to use Excutioner object that doesn't exist anymore.
|
||||
// -> CRASH
|
||||
class Dbms {
|
||||
public:
|
||||
Dbms() {
|
||||
auto snapshot_root_dir = fs::path(FLAGS_snapshot_directory);
|
||||
if (fs::exists(snapshot_root_dir) && !fs::is_directory(snapshot_root_dir)) {
|
||||
throw utils::BasicException("Specified snapshot directory is a file!");
|
||||
}
|
||||
|
||||
if (FLAGS_snapshot_recover_on_startup) {
|
||||
if (fs::exists(snapshot_root_dir)) {
|
||||
auto accessor = dbs.access();
|
||||
for (auto &snapshot_db_dir :
|
||||
fs::directory_iterator(FLAGS_snapshot_directory)) {
|
||||
// The snapshot folder structure is:
|
||||
// snapshot_root_dir/database_name/[timestamp]
|
||||
if (fs::is_directory(snapshot_db_dir)) {
|
||||
// Create db and set it active
|
||||
active(snapshot_db_dir.path().filename(), snapshot_db_dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// create the default database and set is a active
|
||||
active("default");
|
||||
}
|
||||
|
||||
/**
|
||||
* Aborts every transaction in every GraphDb.
|
||||
*/
|
||||
void Shutdown() {
|
||||
alive_ = false;
|
||||
for (auto &db : dbs.access()) {
|
||||
db.second.tx_engine_.ForEachActiveTransaction(
|
||||
[](tx::Transaction &t) { t.set_should_abort(); });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an accessor to the active database. If dbms is shutting down
|
||||
* (alive_ is false) it will reject new transactions and return nullptr.
|
||||
*/
|
||||
std::unique_ptr<GraphDbAccessor> active();
|
||||
|
||||
/**
|
||||
* Set the database with the given name to be active.
|
||||
* If there is no database with the given name,
|
||||
* it's created. If snapshooting is true, snapshooter starts
|
||||
* snapshooting on database creation.
|
||||
*
|
||||
* @return an accessor to the database with the given name.
|
||||
*/
|
||||
std::unique_ptr<GraphDbAccessor> active(
|
||||
const std::string &name, const fs::path &snapshot_db_dir = fs::path());
|
||||
|
||||
// TODO: DELETE action
|
||||
|
||||
private:
|
||||
// dbs container
|
||||
ConcurrentMap<std::string, GraphDb> dbs;
|
||||
|
||||
// currently active database
|
||||
std::atomic<GraphDb *> active_db{nullptr};
|
||||
|
||||
std::atomic<bool> alive_{true};
|
||||
};
|
@ -11,6 +11,15 @@
|
||||
#include "storage/garbage_collector.hpp"
|
||||
#include "utils/timer.hpp"
|
||||
|
||||
bool ValidateSnapshotDirectory(const char *flagname, const std::string &value) {
|
||||
if (fs::exists(value) && !fs::is_directory(value)) {
|
||||
std::cout << "The snapshot directory path '" << value
|
||||
<< "' is not a directory!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
DEFINE_int32(gc_cycle_sec, 30,
|
||||
"Amount of time between starts of two cleaning cycles in seconds. "
|
||||
"-1 to turn off.");
|
||||
@ -22,14 +31,14 @@ DEFINE_int32(snapshot_cycle_sec, -1,
|
||||
DEFINE_int32(query_execution_time_sec, 180,
|
||||
"Maximum allowed query execution time. Queries exceeding this "
|
||||
"limit will be aborted. Value of -1 means no limit.");
|
||||
|
||||
DEFINE_bool(snapshot_on_exit, false, "Snapshot on exiting the database.");
|
||||
DEFINE_string(snapshot_directory, "snapshots",
|
||||
"Path to directory in which to save snapshots.");
|
||||
DEFINE_validator(snapshot_directory, &ValidateSnapshotDirectory);
|
||||
DEFINE_bool(snapshot_recover_on_startup, false, "Recover database on startup.");
|
||||
|
||||
DECLARE_string(snapshot_directory);
|
||||
|
||||
GraphDb::GraphDb(const std::string &name, const fs::path &snapshot_db_dir)
|
||||
: name_(name),
|
||||
gc_vertices_(vertices_, vertex_record_deleter_,
|
||||
GraphDb::GraphDb()
|
||||
: gc_vertices_(vertices_, vertex_record_deleter_,
|
||||
vertex_version_list_deleter_),
|
||||
gc_edges_(edges_, edge_record_deleter_, edge_version_list_deleter_) {
|
||||
// Pause of -1 means we shouldn't run the GC.
|
||||
@ -38,7 +47,9 @@ GraphDb::GraphDb(const std::string &name, const fs::path &snapshot_db_dir)
|
||||
[this]() { CollectGarbage(); });
|
||||
}
|
||||
|
||||
RecoverDatabase(snapshot_db_dir);
|
||||
if (FLAGS_snapshot_recover_on_startup) {
|
||||
RecoverDatabase(FLAGS_snapshot_directory);
|
||||
}
|
||||
StartSnapshooting();
|
||||
|
||||
if (FLAGS_query_execution_time_sec != -1) {
|
||||
@ -57,12 +68,16 @@ GraphDb::GraphDb(const std::string &name, const fs::path &snapshot_db_dir)
|
||||
}
|
||||
}
|
||||
|
||||
void GraphDb::Shutdown() {
|
||||
is_accepting_transactions_ = false;
|
||||
tx_engine_.ForEachActiveTransaction([](auto &t) { t.set_should_abort(); });
|
||||
}
|
||||
|
||||
void GraphDb::StartSnapshooting() {
|
||||
if (FLAGS_snapshot_cycle_sec != -1) {
|
||||
auto create_snapshot = [this]() -> void {
|
||||
GraphDbAccessor db_accessor(*this);
|
||||
snapshooter_.MakeSnapshot(db_accessor,
|
||||
fs::path(FLAGS_snapshot_directory) / name_,
|
||||
snapshooter_.MakeSnapshot(db_accessor, fs::path(FLAGS_snapshot_directory),
|
||||
FLAGS_snapshot_max_retained);
|
||||
};
|
||||
snapshot_creator_.Run(std::chrono::seconds(FLAGS_snapshot_cycle_sec),
|
||||
@ -162,7 +177,7 @@ GraphDb::~GraphDb() {
|
||||
GraphDbAccessor db_accessor(*this);
|
||||
LOG(INFO) << "Creating snapshot on shutdown..." << std::endl;
|
||||
const bool status = snapshooter_.MakeSnapshot(
|
||||
db_accessor, fs::path(FLAGS_snapshot_directory) / name_,
|
||||
db_accessor, fs::path(FLAGS_snapshot_directory),
|
||||
FLAGS_snapshot_max_retained);
|
||||
if (status) {
|
||||
std::cout << "Snapshot created successfully." << std::endl;
|
||||
|
@ -23,43 +23,55 @@
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
// TODO: Maybe split this in another layer between Db and Dbms. Where the new
|
||||
// layer would hold SnapshotEngine and his kind of concept objects. Some
|
||||
// guidelines would be: retain objects which are necessary to implement querys
|
||||
// in Db, the rest can be moved to the new layer.
|
||||
/**
|
||||
* Main class which represents Database concept in code.
|
||||
* This class is essentially a data structure. It exposes
|
||||
* all the data publicly, and should therefore not be directly
|
||||
* exposed to client functions. The GraphDbAccessor is used for that.
|
||||
*
|
||||
* Always be sure that GraphDb object is destructed before main exits, i. e.
|
||||
* GraphDb object shouldn't be part of global/static variable, except if its
|
||||
* destructor is explicitly called before main exits. Consider code:
|
||||
*
|
||||
* GraphDb db; // KeyIndex is created as a part of db.
|
||||
* int main() {
|
||||
* GraphDbAccessor dba(db);
|
||||
* auto v = dba.InsertVertex();
|
||||
* v.add_label(dba.Label(
|
||||
* "Start")); // New SkipList is created in KeyIndex for LabelIndex.
|
||||
* // That SkipList creates SkipListGc which
|
||||
* // initialises static Executor object.
|
||||
* return 0;
|
||||
* }
|
||||
*
|
||||
* After main exits: 1. Executor is destructed, 2. KeyIndex is destructed.
|
||||
* Destructor of KeyIndex calls delete on created SkipLists which destroy
|
||||
* SkipListGc that tries to use Excutioner object that doesn't exist anymore.
|
||||
* -> CRASH
|
||||
*/
|
||||
class GraphDb {
|
||||
public:
|
||||
/**
|
||||
* Construct database with a custom name.
|
||||
*
|
||||
* @param name database name
|
||||
* @param import_snapshot will in constructor import latest snapshot
|
||||
* into the db.
|
||||
*/
|
||||
GraphDb(const std::string &name, const fs::path &snapshot_db_dir);
|
||||
/**
|
||||
* @brief - Destruct database object. Delete all vertices and edges and free
|
||||
* all deferred deleters.
|
||||
*/
|
||||
GraphDb();
|
||||
/** Delete all vertices and edges and free all deferred deleters. */
|
||||
~GraphDb();
|
||||
|
||||
/**
|
||||
* Database object can't be copied.
|
||||
*/
|
||||
/** Database object can't be copied. */
|
||||
GraphDb(const GraphDb &db) = delete;
|
||||
GraphDb(GraphDb &&other) = default;
|
||||
GraphDb &operator=(const GraphDb &other) = default;
|
||||
GraphDb &operator=(GraphDb &&other) = default;
|
||||
|
||||
/**
|
||||
* Starts database snapshooting.
|
||||
*/
|
||||
/** Stop all transactions and set is_accepting_transactions_ to false. */
|
||||
void Shutdown();
|
||||
|
||||
void CollectGarbage();
|
||||
|
||||
/** When this is false, no new transactions should be created. */
|
||||
std::atomic<bool> is_accepting_transactions_{true};
|
||||
|
||||
private:
|
||||
friend class GraphDbAccessor;
|
||||
|
||||
void StartSnapshooting();
|
||||
|
||||
/**
|
||||
@ -68,17 +80,9 @@ class GraphDb {
|
||||
*/
|
||||
void RecoverDatabase(const fs::path &snapshot_db_path);
|
||||
|
||||
/**
|
||||
* Collects garbage.
|
||||
*/
|
||||
void CollectGarbage();
|
||||
|
||||
/** transaction engine related to this database */
|
||||
tx::Engine tx_engine_;
|
||||
|
||||
// database name
|
||||
const std::string name_;
|
||||
|
||||
// main storage for the graph
|
||||
SkipList<mvcc::VersionList<Vertex> *> vertices_;
|
||||
SkipList<mvcc::VersionList<Edge> *> edges_;
|
||||
@ -105,10 +109,12 @@ class GraphDb {
|
||||
KeyIndex<GraphDbTypes::Label, Vertex> labels_index_;
|
||||
LabelPropertyIndex label_property_index_;
|
||||
|
||||
// Flag indicating if index building is in progress. Memgraph does not support
|
||||
// concurrent index builds on the same database (transaction engine), so we
|
||||
// reject index builds if there is one in progress. See
|
||||
// GraphDbAccessor::BuildIndex.
|
||||
/**
|
||||
* Flag indicating if index building is in progress. Memgraph does not support
|
||||
* concurrent index builds on the same database (transaction engine), so we
|
||||
* reject index builds if there is one in progress. See
|
||||
* GraphDbAccessor::BuildIndex.
|
||||
*/
|
||||
std::atomic<bool> index_build_in_progress_{false};
|
||||
|
||||
// snapshooter
|
||||
@ -121,6 +127,6 @@ class GraphDb {
|
||||
// time to stop their execution.
|
||||
Scheduler transaction_killer_;
|
||||
|
||||
// DB level global counters, used in the "counter" function
|
||||
/** DB level global counters, used in the "counter" function. */
|
||||
ConcurrentMap<std::string, std::atomic<int64_t>> counters_;
|
||||
};
|
||||
|
@ -16,8 +16,6 @@ GraphDbAccessor::~GraphDbAccessor() {
|
||||
}
|
||||
}
|
||||
|
||||
const std::string &GraphDbAccessor::name() const { return db_.name_; }
|
||||
|
||||
void GraphDbAccessor::AdvanceCommand() {
|
||||
DCHECK(!commited_ && !aborted_) << "Accessor committed or aborted";
|
||||
transaction_->engine_.Advance(transaction_->id_);
|
||||
|
@ -65,11 +65,6 @@ class GraphDbAccessor {
|
||||
GraphDbAccessor &operator=(const GraphDbAccessor &other) = delete;
|
||||
GraphDbAccessor &operator=(GraphDbAccessor &&other) = delete;
|
||||
|
||||
/**
|
||||
* Returns the name of the database of this accessor.
|
||||
*/
|
||||
const std::string &name() const;
|
||||
|
||||
/**
|
||||
* Creates a new Vertex and returns an accessor to it.
|
||||
*
|
||||
|
@ -19,9 +19,9 @@
|
||||
#include "version.hpp"
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
using communication::bolt::SessionData;
|
||||
using io::network::NetworkEndpoint;
|
||||
using io::network::Socket;
|
||||
using communication::bolt::SessionData;
|
||||
using SessionT = communication::bolt::Session<Socket>;
|
||||
using ResultStreamT = SessionT::ResultStreamT;
|
||||
using ServerT = communication::Server<SessionT, SessionData>;
|
||||
@ -70,7 +70,7 @@ int main(int argc, char **argv) {
|
||||
<< stacktrace.dump() << std::endl;
|
||||
});
|
||||
|
||||
// Initialize bolt session data (Dbms and Interpreter).
|
||||
// Initialize bolt session data (GraphDb and Interpreter).
|
||||
SessionData session_data;
|
||||
|
||||
// Initialize endpoint.
|
||||
@ -85,18 +85,17 @@ int main(int argc, char **argv) {
|
||||
// Initialize server.
|
||||
ServerT server(endpoint, session_data);
|
||||
|
||||
auto shutdown = [&server, &session_data]() {
|
||||
// Server needs to be shutdown first and then the database. This prevents a
|
||||
// race condition when a transaction is accepted during server shutdown.
|
||||
server.Shutdown();
|
||||
session_data.db.Shutdown();
|
||||
};
|
||||
// register SIGTERM handler
|
||||
SignalHandler::register_handler(Signal::Terminate,
|
||||
[&server, &session_data]() {
|
||||
server.Shutdown();
|
||||
session_data.dbms.Shutdown();
|
||||
});
|
||||
SignalHandler::register_handler(Signal::Terminate, shutdown);
|
||||
|
||||
// register SIGINT handler
|
||||
SignalHandler::register_handler(Signal::Interupt, [&server, &session_data]() {
|
||||
server.Shutdown();
|
||||
session_data.dbms.Shutdown();
|
||||
});
|
||||
SignalHandler::register_handler(Signal::Interupt, shutdown);
|
||||
|
||||
// Start memory warning logger.
|
||||
Scheduler mem_log_scheduler;
|
||||
|
@ -123,7 +123,7 @@ void PrintResults(const ResultStreamFaker &results) {
|
||||
std::cout << "}" << std::endl;
|
||||
}
|
||||
|
||||
void query::Repl(Dbms &dbms) {
|
||||
void query::Repl(GraphDb &db) {
|
||||
std::cout
|
||||
<< "Welcome to *Awesome* Memgraph Read Evaluate Print Loop (AM-REPL)"
|
||||
<< std::endl;
|
||||
@ -138,11 +138,11 @@ void query::Repl(Dbms &dbms) {
|
||||
|
||||
// regular cypher queries
|
||||
try {
|
||||
auto dba = dbms.active();
|
||||
GraphDbAccessor dba(db);
|
||||
ResultStreamFaker results;
|
||||
interpeter.Interpret(command, *dba, results, {}, false);
|
||||
interpeter.Interpret(command, dba, results, {}, false);
|
||||
PrintResults(results);
|
||||
dba->Commit();
|
||||
dba.Commit();
|
||||
} catch (const query::SyntaxException &e) {
|
||||
std::cout << "SYNTAX EXCEPTION: " << e.what() << std::endl;
|
||||
} catch (const query::LexingException &e) {
|
||||
|
@ -8,16 +8,14 @@
|
||||
#include <list>
|
||||
|
||||
#include "communication/result_stream_faker.hpp"
|
||||
#include "database/dbms.hpp"
|
||||
|
||||
namespace query {
|
||||
|
||||
/**
|
||||
* Read Evaluate Print Loop,
|
||||
* for interacting with a database
|
||||
* (the active database in the given DBMS).
|
||||
* Immediately starts the user-input loop
|
||||
* and interprets the entered queries.
|
||||
* Read Evaluate Print Loop, for interacting with a database (the database in
|
||||
* the given GraphDb). Immediately starts the user-input loop and interprets the
|
||||
* entered queries.
|
||||
*/
|
||||
void Repl(Dbms &dbms);
|
||||
}
|
||||
void Repl(GraphDb &);
|
||||
|
||||
} // namespace query
|
||||
|
@ -7,12 +7,12 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <experimental/optional>
|
||||
#include <functional>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include "data_structures/concurrent/skiplist.hpp"
|
||||
#include "database/dbms.hpp"
|
||||
#include "database/graph_db_datatypes.hpp"
|
||||
#include "mvcc/version_list.hpp"
|
||||
#include "storage/property_value.hpp"
|
||||
@ -37,7 +37,7 @@ auto RandomIntGenerator(int from, int to) {
|
||||
*/
|
||||
class RandomGraphGenerator {
|
||||
public:
|
||||
explicit RandomGraphGenerator(Dbms &dbms) : dbms_(dbms) {}
|
||||
explicit RandomGraphGenerator(GraphDb &db) : db_(db) {}
|
||||
|
||||
/**
|
||||
* Adds a progress listener that gets notified when
|
||||
@ -65,10 +65,10 @@ class RandomGraphGenerator {
|
||||
*/
|
||||
void AddVertices(int count, const std::vector<std::string> &label_names,
|
||||
int thread_count, int batch_size = 2000) {
|
||||
auto dba = dbms_.active();
|
||||
GraphDbAccessor dba(db_);
|
||||
std::vector<GraphDbTypes::Label> labels;
|
||||
for (const auto &label_name : label_names)
|
||||
labels.push_back(dba->Label(label_name));
|
||||
labels.push_back(dba.Label(label_name));
|
||||
|
||||
Map(
|
||||
[&labels, this](GraphDbAccessor &dba) {
|
||||
@ -83,7 +83,7 @@ class RandomGraphGenerator {
|
||||
* Returns the number of vertices created by this generator,
|
||||
* regardless of their labels.
|
||||
*/
|
||||
int64_t VertexCount() const { return dbms_.active()->VerticesCount(); }
|
||||
int64_t VertexCount() const { return GraphDbAccessor(db_).VerticesCount(); }
|
||||
|
||||
/**
|
||||
* Adds the given number of edges to the graph.
|
||||
@ -106,12 +106,12 @@ class RandomGraphGenerator {
|
||||
auto vertices_from = FilterVertices(from_filter);
|
||||
auto vertices_to = FilterVertices(to_filter);
|
||||
|
||||
auto dba = dbms_.active();
|
||||
auto edge_type = dba->EdgeType(edge_type_name);
|
||||
GraphDbAccessor dba(db_);
|
||||
auto edge_type = dba.EdgeType(edge_type_name);
|
||||
|
||||
// for small vertex counts reduce the batch size
|
||||
batch_size =
|
||||
std::min(batch_size, static_cast<int>(dba->VerticesCount() / 1000 + 1));
|
||||
std::min(batch_size, static_cast<int>(dba.VerticesCount() / 1000 + 1));
|
||||
|
||||
Map(
|
||||
[&vertices_from, &vertices_to, edge_type, this](GraphDbAccessor &dba) {
|
||||
@ -130,7 +130,7 @@ class RandomGraphGenerator {
|
||||
* Returns the number of edges created by this generator,
|
||||
* regardless of their types and origin/destination labels.
|
||||
*/
|
||||
int64_t EdgeCount() const { return dbms_.active()->EdgesCount(); }
|
||||
int64_t EdgeCount() const { return GraphDbAccessor(db_).EdgesCount(); }
|
||||
|
||||
/**
|
||||
* Sets a generated property on a random vertex.
|
||||
@ -146,15 +146,15 @@ class RandomGraphGenerator {
|
||||
const std::string &prop_name, std::function<TValue()> value_generator,
|
||||
std::function<bool(VertexAccessor &va)> predicate = {}) {
|
||||
if (!predicate) predicate = [](VertexAccessor &) { return true; };
|
||||
auto dba = dbms_.active();
|
||||
auto property = dba->Property(prop_name);
|
||||
for (VertexAccessor va : dba->Vertices(false))
|
||||
GraphDbAccessor dba(db_);
|
||||
auto property = dba.Property(prop_name);
|
||||
for (VertexAccessor va : dba.Vertices(false))
|
||||
if (predicate(va)) va.PropsSet(property, value_generator());
|
||||
dba->Commit();
|
||||
dba.Commit();
|
||||
}
|
||||
|
||||
private:
|
||||
Dbms &dbms_;
|
||||
GraphDb &db_;
|
||||
|
||||
// progress listeners, they get notified about vertices and edges being
|
||||
// created
|
||||
@ -167,7 +167,7 @@ class RandomGraphGenerator {
|
||||
*
|
||||
*
|
||||
* @param predicate A predicate. By default always true.
|
||||
* @return A vector of vertex accessors. They belong to a GraphDbAccesor
|
||||
* @return A vector of vertex accessors. They belong to a GraphDbAccessor
|
||||
* that is dead when this function retuns, make sure to
|
||||
* GraphDbAccessor::Transfer them.
|
||||
*/
|
||||
@ -175,8 +175,8 @@ class RandomGraphGenerator {
|
||||
std::function<bool(VertexAccessor &item)> predicate = {}) {
|
||||
if (!predicate) predicate = [](VertexAccessor &) { return true; };
|
||||
std::vector<VertexAccessor> r_val;
|
||||
auto dba = dbms_.active();
|
||||
for (VertexAccessor &item : dba->Vertices(false))
|
||||
GraphDbAccessor dba(db_);
|
||||
for (VertexAccessor &item : dba.Vertices(false))
|
||||
if (predicate(item)) r_val.emplace_back(item);
|
||||
|
||||
return r_val;
|
||||
@ -204,7 +204,7 @@ class RandomGraphGenerator {
|
||||
for (int thread_ind = 0; thread_ind < thread_count; thread_ind++) {
|
||||
if (thread_ind == thread_count - 1) count_per_thread += count_remainder;
|
||||
threads.emplace_back([count_per_thread, &f, this, elements_per_commit]() {
|
||||
auto dba = dbms_.active();
|
||||
std::experimental::optional<GraphDbAccessor> dba(db_);
|
||||
for (int i = 0; i < count_per_thread; i++) {
|
||||
try {
|
||||
f(*dba);
|
||||
@ -218,8 +218,8 @@ class RandomGraphGenerator {
|
||||
if (i == (count_per_thread - 1) ||
|
||||
(i >= 0 && i % elements_per_commit == 0)) {
|
||||
dba->Commit();
|
||||
auto dba2 = dbms_.active();
|
||||
dba.swap(dba2);
|
||||
dba = std::experimental::nullopt;
|
||||
dba.emplace(db_);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -3,47 +3,46 @@
|
||||
#include <glog/logging.h>
|
||||
|
||||
#include "communication/result_stream_faker.hpp"
|
||||
#include "database/dbms.hpp"
|
||||
#include "query/interpreter.hpp"
|
||||
#include "query/typed_value.hpp"
|
||||
|
||||
class ExpansionBenchFixture : public benchmark::Fixture {
|
||||
protected:
|
||||
// Dbms shouldn't be global constructed/destructed. See documentation in
|
||||
// database/dbms.hpp for details.
|
||||
std::experimental::optional<Dbms> dbms_;
|
||||
// GraphDb shouldn't be global constructed/destructed. See documentation in
|
||||
// database/graph_db.hpp for details.
|
||||
std::experimental::optional<GraphDb> db_;
|
||||
query::Interpreter interpeter_;
|
||||
|
||||
void SetUp(const benchmark::State &state) override {
|
||||
dbms_.emplace();
|
||||
auto dba = dbms_->active();
|
||||
for (int i = 0; i < state.range(0); i++) dba->InsertVertex();
|
||||
db_.emplace();
|
||||
GraphDbAccessor dba(*db_);
|
||||
for (int i = 0; i < state.range(0); i++) dba.InsertVertex();
|
||||
|
||||
// the fixed part is one vertex expanding to 1000 others
|
||||
auto start = dba->InsertVertex();
|
||||
start.add_label(dba->Label("Start"));
|
||||
auto edge_type = dba->EdgeType("edge_type");
|
||||
auto start = dba.InsertVertex();
|
||||
start.add_label(dba.Label("Start"));
|
||||
auto edge_type = dba.EdgeType("edge_type");
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
auto dest = dba->InsertVertex();
|
||||
dba->InsertEdge(start, dest, edge_type);
|
||||
auto dest = dba.InsertVertex();
|
||||
dba.InsertEdge(start, dest, edge_type);
|
||||
}
|
||||
dba->Commit();
|
||||
dba.Commit();
|
||||
}
|
||||
|
||||
void TearDown(const benchmark::State &) override {
|
||||
auto dba = dbms_->active();
|
||||
for (auto vertex : dba->Vertices(false)) dba->DetachRemoveVertex(vertex);
|
||||
dba->Commit();
|
||||
dbms_ = std::experimental::nullopt;
|
||||
GraphDbAccessor dba(*db_);
|
||||
for (auto vertex : dba.Vertices(false)) dba.DetachRemoveVertex(vertex);
|
||||
dba.Commit();
|
||||
db_ = std::experimental::nullopt;
|
||||
}
|
||||
};
|
||||
|
||||
BENCHMARK_DEFINE_F(ExpansionBenchFixture, Match)(benchmark::State &state) {
|
||||
auto query = "MATCH (s:Start) return s";
|
||||
auto dba = dbms_->active();
|
||||
GraphDbAccessor dba(*db_);
|
||||
while (state.KeepRunning()) {
|
||||
ResultStreamFaker results;
|
||||
interpeter_.Interpret(query, *dba, results, {}, false);
|
||||
interpeter_.Interpret(query, dba, results, {}, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -54,10 +53,10 @@ BENCHMARK_REGISTER_F(ExpansionBenchFixture, Match)
|
||||
|
||||
BENCHMARK_DEFINE_F(ExpansionBenchFixture, Expand)(benchmark::State &state) {
|
||||
auto query = "MATCH (s:Start) WITH s MATCH (s)--(d) RETURN count(d)";
|
||||
auto dba = dbms_->active();
|
||||
GraphDbAccessor dba(*db_);
|
||||
while (state.KeepRunning()) {
|
||||
ResultStreamFaker results;
|
||||
interpeter_.Interpret(query, *dba, results, {}, false);
|
||||
interpeter_.Interpret(query, dba, results, {}, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
#include <benchmark/benchmark_api.h>
|
||||
|
||||
#include "database/dbms.hpp"
|
||||
#include "query/frontend/semantic/symbol_generator.hpp"
|
||||
#include "query/plan/cost_estimator.hpp"
|
||||
#include "query/plan/planner.hpp"
|
||||
@ -28,8 +27,8 @@ static void AddChainedMatches(int num_matches, query::AstTreeStorage &storage) {
|
||||
}
|
||||
|
||||
static void BM_PlanChainedMatches(benchmark::State &state) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
while (state.KeepRunning()) {
|
||||
state.PauseTiming();
|
||||
query::AstTreeStorage storage;
|
||||
@ -38,7 +37,7 @@ static void BM_PlanChainedMatches(benchmark::State &state) {
|
||||
query::SymbolTable symbol_table;
|
||||
query::SymbolGenerator symbol_generator(symbol_table);
|
||||
storage.query()->Accept(symbol_generator);
|
||||
auto ctx = query::plan::MakePlanningContext(storage, symbol_table, *dba);
|
||||
auto ctx = query::plan::MakePlanningContext(storage, symbol_table, dba);
|
||||
state.ResumeTiming();
|
||||
query::plan::LogicalOperator *current_plan;
|
||||
auto plans =
|
||||
@ -75,32 +74,30 @@ static void AddIndexedMatches(
|
||||
}
|
||||
|
||||
static auto CreateIndexedVertices(int index_count, int vertex_count,
|
||||
Dbms &dbms) {
|
||||
auto dba = dbms.active();
|
||||
auto label = dba->Label("label");
|
||||
auto prop = dba->Property("prop");
|
||||
dba->BuildIndex(label, prop);
|
||||
dba = dbms.active();
|
||||
GraphDb &db) {
|
||||
auto label = GraphDbAccessor(db).Label("label");
|
||||
auto prop = GraphDbAccessor(db).Property("prop");
|
||||
GraphDbAccessor(db).BuildIndex(label, prop);
|
||||
GraphDbAccessor dba(db);
|
||||
for (int vi = 0; vi < vertex_count; ++vi) {
|
||||
for (int index = 0; index < index_count; ++index) {
|
||||
auto vertex = dba->InsertVertex();
|
||||
auto vertex = dba.InsertVertex();
|
||||
vertex.add_label(label);
|
||||
vertex.PropsSet(prop, index);
|
||||
}
|
||||
}
|
||||
dba->Commit();
|
||||
dba.Commit();
|
||||
return std::make_pair(label, prop);
|
||||
}
|
||||
|
||||
static void BM_PlanAndEstimateIndexedMatching(benchmark::State &state) {
|
||||
Dbms dbms;
|
||||
GraphDb db;
|
||||
GraphDbTypes::Label label;
|
||||
GraphDbTypes::Property prop;
|
||||
int index_count = state.range(0);
|
||||
int vertex_count = state.range(1);
|
||||
std::tie(label, prop) =
|
||||
CreateIndexedVertices(index_count, vertex_count, dbms);
|
||||
auto dba = dbms.active();
|
||||
std::tie(label, prop) = CreateIndexedVertices(index_count, vertex_count, db);
|
||||
GraphDbAccessor dba(db);
|
||||
Parameters parameters;
|
||||
while (state.KeepRunning()) {
|
||||
state.PauseTiming();
|
||||
@ -111,26 +108,25 @@ static void BM_PlanAndEstimateIndexedMatching(benchmark::State &state) {
|
||||
query::SymbolGenerator symbol_generator(symbol_table);
|
||||
storage.query()->Accept(symbol_generator);
|
||||
state.ResumeTiming();
|
||||
auto ctx = query::plan::MakePlanningContext(storage, symbol_table, *dba);
|
||||
auto ctx = query::plan::MakePlanningContext(storage, symbol_table, dba);
|
||||
auto plans =
|
||||
query::plan::MakeLogicalPlan<query::plan::VariableStartPlanner>(ctx);
|
||||
for (auto plan : plans) {
|
||||
query::plan::EstimatePlanCost(*dba, parameters, *plan);
|
||||
query::plan::EstimatePlanCost(dba, parameters, *plan);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void BM_PlanAndEstimateIndexedMatchingWithCachedCounts(
|
||||
benchmark::State &state) {
|
||||
Dbms dbms;
|
||||
GraphDb db;
|
||||
GraphDbTypes::Label label;
|
||||
GraphDbTypes::Property prop;
|
||||
int index_count = state.range(0);
|
||||
int vertex_count = state.range(1);
|
||||
std::tie(label, prop) =
|
||||
CreateIndexedVertices(index_count, vertex_count, dbms);
|
||||
auto dba = dbms.active();
|
||||
auto vertex_counts = query::plan::MakeVertexCountCache(*dba);
|
||||
std::tie(label, prop) = CreateIndexedVertices(index_count, vertex_count, db);
|
||||
GraphDbAccessor dba(db);
|
||||
auto vertex_counts = query::plan::MakeVertexCountCache(dba);
|
||||
Parameters parameters;
|
||||
while (state.KeepRunning()) {
|
||||
state.PauseTiming();
|
||||
|
@ -5,7 +5,6 @@
|
||||
#include <gflags/gflags.h>
|
||||
#include <glog/logging.h>
|
||||
|
||||
#include "database/dbms.hpp"
|
||||
#include "query/console.hpp"
|
||||
#include "query/interpreter.hpp"
|
||||
#include "utils/random_graph_generator.hpp"
|
||||
@ -44,8 +43,8 @@ class ProgressReporter {
|
||||
std::mutex mutex_{};
|
||||
};
|
||||
|
||||
void random_generate(Dbms &dbms, int64_t node_count, int64_t edge_count) {
|
||||
utils::RandomGraphGenerator generator(dbms);
|
||||
void random_generate(GraphDb &db, int64_t node_count, int64_t edge_count) {
|
||||
utils::RandomGraphGenerator generator(db);
|
||||
ProgressReporter reporter(node_count, edge_count,
|
||||
std::max(1l, (node_count + edge_count) / 100));
|
||||
generator.AddProgressListener([&reporter](auto &rgg) { reporter(rgg); });
|
||||
@ -70,10 +69,10 @@ int main(int argc, char *argv[]) {
|
||||
// TODO switch to GFlags, once finally available
|
||||
if (argc > 3) google::InitGoogleLogging(argv[0]);
|
||||
|
||||
Dbms dbms;
|
||||
GraphDb db;
|
||||
std::cout << "Generating graph..." << std::endl;
|
||||
// fill_db(dbms);
|
||||
random_generate(dbms, node_count, edge_count);
|
||||
query::Repl(dbms);
|
||||
// fill_db;
|
||||
random_generate(db, node_count, edge_count);
|
||||
query::Repl(db);
|
||||
return 0;
|
||||
}
|
||||
|
@ -10,7 +10,6 @@
|
||||
#include "gflags/gflags.h"
|
||||
#include "glog/logging.h"
|
||||
|
||||
#include "database/dbms.hpp"
|
||||
#include "query/context.hpp"
|
||||
#include "query/frontend/ast/ast.hpp"
|
||||
#include "query/frontend/ast/cypher_main_visitor.hpp"
|
||||
@ -646,7 +645,7 @@ int main(int argc, char *argv[]) {
|
||||
std::cerr << "File '" << in_db_filename << "' does not exist!" << std::endl;
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
Dbms dbms;
|
||||
GraphDb db;
|
||||
Timer planning_timer;
|
||||
InteractiveDbAccessor interactive_db(
|
||||
in_db_filename.empty() ? ReadInt("Vertices in DB: ") : 0, planning_timer);
|
||||
@ -659,8 +658,8 @@ int main(int argc, char *argv[]) {
|
||||
if (!line || *line == "quit") break;
|
||||
if (line->empty()) continue;
|
||||
try {
|
||||
auto dba = dbms.active();
|
||||
auto ast = MakeAst(*line, *dba);
|
||||
GraphDbAccessor dba(db);
|
||||
auto ast = MakeAst(*line, dba);
|
||||
auto symbol_table = MakeSymbolTable(ast);
|
||||
planning_timer.Start();
|
||||
auto plans = MakeLogicalPlans(ast, symbol_table, interactive_db);
|
||||
|
@ -1,37 +1,41 @@
|
||||
#include <rapidcheck.h>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include "database/dbms.hpp"
|
||||
|
||||
/**
|
||||
* gtest/gtest.h must be included before rapidcheck/gtest.h!
|
||||
*/
|
||||
#include "gtest/gtest.h"
|
||||
#include <gtest/gtest.h>
|
||||
#include <rapidcheck.h>
|
||||
#include <rapidcheck/gtest.h>
|
||||
|
||||
#include "database/graph_db.hpp"
|
||||
#include "database/graph_db_accessor.hpp"
|
||||
#include "storage/vertex_accessor.hpp"
|
||||
|
||||
/**
|
||||
* It is possible to run test with custom seed with:
|
||||
* RC_PARAMS="seed=1" ./random_graph
|
||||
*/
|
||||
RC_GTEST_PROP(RandomGraph, RandomGraph, (std::vector<std::string> vertex_labels,
|
||||
std::vector<std::string> edge_types)) {
|
||||
RC_GTEST_PROP(RandomGraph, RandomGraph,
|
||||
(std::vector<std::string> vertex_labels,
|
||||
std::vector<std::string> edge_types)) {
|
||||
RC_PRE(!vertex_labels.empty());
|
||||
RC_PRE(!edge_types.empty());
|
||||
|
||||
int vertices_num = vertex_labels.size();
|
||||
int edges_num = edge_types.size();
|
||||
|
||||
Dbms dbms;
|
||||
GraphDb db;
|
||||
std::vector<VertexAccessor> vertices;
|
||||
std::map<VertexAccessor, std::string> vertex_label_map;
|
||||
std::map<EdgeAccessor, std::string> edge_type_map;
|
||||
|
||||
auto dba = dbms.active();
|
||||
GraphDbAccessor dba(db);
|
||||
|
||||
for (auto label : vertex_labels) {
|
||||
auto vertex_accessor = dba->InsertVertex();
|
||||
vertex_accessor.add_label(dba->Label(label));
|
||||
auto vertex_accessor = dba.InsertVertex();
|
||||
vertex_accessor.add_label(dba.Label(label));
|
||||
vertex_label_map.insert({vertex_accessor, label});
|
||||
vertices.push_back(vertex_accessor);
|
||||
}
|
||||
@ -39,21 +43,21 @@ RC_GTEST_PROP(RandomGraph, RandomGraph, (std::vector<std::string> vertex_labels,
|
||||
for (auto type : edge_types) {
|
||||
auto from = vertices[*rc::gen::inRange(0, vertices_num)];
|
||||
auto to = vertices[*rc::gen::inRange(0, vertices_num)];
|
||||
auto edge_accessor = dba->InsertEdge(from, to, dba->EdgeType(type));
|
||||
auto edge_accessor = dba.InsertEdge(from, to, dba.EdgeType(type));
|
||||
edge_type_map.insert({edge_accessor, type});
|
||||
}
|
||||
|
||||
dba->AdvanceCommand();
|
||||
dba.AdvanceCommand();
|
||||
|
||||
int edges_num_check = 0;
|
||||
int vertices_num_check = 0;
|
||||
for (const auto &vertex : dba->Vertices(false)) {
|
||||
for (const auto &vertex : dba.Vertices(false)) {
|
||||
auto label = vertex_label_map.at(vertex);
|
||||
RC_ASSERT(vertex.labels().size() == 1);
|
||||
RC_ASSERT(*vertex.labels()[0] == label);
|
||||
vertices_num_check++;
|
||||
}
|
||||
for (const auto &edge : dba->Edges(false)) {
|
||||
for (const auto &edge : dba.Edges(false)) {
|
||||
auto type = edge_type_map.at(edge);
|
||||
RC_ASSERT(*edge.EdgeType() == type);
|
||||
edges_num_check++;
|
||||
|
@ -2,7 +2,6 @@
|
||||
#include "bolt_testdata.hpp"
|
||||
|
||||
#include "communication/bolt/v1/encoder/encoder.hpp"
|
||||
#include "database/dbms.hpp"
|
||||
#include "database/graph_db.hpp"
|
||||
#include "database/graph_db_accessor.hpp"
|
||||
#include "query/typed_value.hpp"
|
||||
@ -165,10 +164,10 @@ TEST(BoltEncoder, VertexAndEdge) {
|
||||
output.clear();
|
||||
|
||||
// create vertex
|
||||
Dbms dbms;
|
||||
auto db_accessor = dbms.active();
|
||||
auto va1 = db_accessor->InsertVertex();
|
||||
auto va2 = db_accessor->InsertVertex();
|
||||
GraphDb db;
|
||||
GraphDbAccessor db_accessor(db);
|
||||
auto va1 = db_accessor.InsertVertex();
|
||||
auto va2 = db_accessor.InsertVertex();
|
||||
std::string l1("label1"), l2("label2");
|
||||
va1.add_label(&l1);
|
||||
va1.add_label(&l2);
|
||||
@ -179,7 +178,7 @@ TEST(BoltEncoder, VertexAndEdge) {
|
||||
|
||||
// create edge
|
||||
std::string et("edgetype");
|
||||
auto ea = db_accessor->InsertEdge(va1, va2, &et);
|
||||
auto ea = db_accessor.InsertEdge(va1, va2, &et);
|
||||
std::string p3("prop3"), p4("prop4");
|
||||
PropertyValue pv3(42), pv4(1234);
|
||||
ea.PropsSet(&p3, pv3);
|
||||
|
@ -6,7 +6,6 @@
|
||||
#include <vector>
|
||||
|
||||
#include "antlr4-runtime.h"
|
||||
#include "database/dbms.hpp"
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "query/context.hpp"
|
||||
@ -21,21 +20,21 @@ namespace {
|
||||
using namespace query;
|
||||
using namespace query::frontend;
|
||||
using query::TypedValue;
|
||||
using testing::Pair;
|
||||
using testing::ElementsAre;
|
||||
using testing::Pair;
|
||||
using testing::UnorderedElementsAre;
|
||||
|
||||
// Base class for all test types
|
||||
class Base {
|
||||
public:
|
||||
Base(const std::string &query) : query_string_(query) {}
|
||||
Dbms dbms_;
|
||||
std::unique_ptr<GraphDbAccessor> db_accessor_ = dbms_.active();
|
||||
Context context_{*db_accessor_};
|
||||
GraphDb db_;
|
||||
GraphDbAccessor db_accessor_{db_};
|
||||
Context context_{db_accessor_};
|
||||
std::string query_string_;
|
||||
|
||||
auto Prop(const std::string &prop_name) {
|
||||
return db_accessor_->Property(prop_name);
|
||||
return db_accessor_.Property(prop_name);
|
||||
}
|
||||
|
||||
auto PropPair(const std::string &prop_name) {
|
||||
@ -136,7 +135,7 @@ TYPED_TEST(CypherMainVisitorTest, PropertyLookup) {
|
||||
ASSERT_TRUE(identifier);
|
||||
ASSERT_EQ(identifier->name_, "n");
|
||||
ASSERT_EQ(property_lookup->property_,
|
||||
ast_generator.db_accessor_->Property("x"));
|
||||
ast_generator.db_accessor_.Property("x"));
|
||||
}
|
||||
|
||||
TYPED_TEST(CypherMainVisitorTest, LabelsTest) {
|
||||
@ -151,8 +150,8 @@ TYPED_TEST(CypherMainVisitorTest, LabelsTest) {
|
||||
ASSERT_TRUE(identifier);
|
||||
ASSERT_EQ(identifier->name_, "n");
|
||||
ASSERT_THAT(labels_test->labels_,
|
||||
ElementsAre(ast_generator.db_accessor_->Label("x"),
|
||||
ast_generator.db_accessor_->Label("y")));
|
||||
ElementsAre(ast_generator.db_accessor_.Label("x"),
|
||||
ast_generator.db_accessor_.Label("y")));
|
||||
}
|
||||
|
||||
TYPED_TEST(CypherMainVisitorTest, EscapedLabel) {
|
||||
@ -165,7 +164,7 @@ TYPED_TEST(CypherMainVisitorTest, EscapedLabel) {
|
||||
auto identifier = dynamic_cast<Identifier *>(labels_test->expression_);
|
||||
ASSERT_EQ(identifier->name_, "n");
|
||||
ASSERT_THAT(labels_test->labels_,
|
||||
ElementsAre(ast_generator.db_accessor_->Label("l-$\"'ab`e``l")));
|
||||
ElementsAre(ast_generator.db_accessor_.Label("l-$\"'ab`e``l")));
|
||||
}
|
||||
|
||||
TYPED_TEST(CypherMainVisitorTest, KeywordLabel) {
|
||||
@ -182,7 +181,7 @@ TYPED_TEST(CypherMainVisitorTest, HexLetterLabel) {
|
||||
auto identifier = dynamic_cast<Identifier *>(labels_test->expression_);
|
||||
EXPECT_EQ(identifier->name_, "n");
|
||||
ASSERT_THAT(labels_test->labels_,
|
||||
ElementsAre(ast_generator.db_accessor_->Label("a")));
|
||||
ElementsAre(ast_generator.db_accessor_.Label("a")));
|
||||
}
|
||||
|
||||
TYPED_TEST(CypherMainVisitorTest, ReturnNoDistinctNoBagSemantics) {
|
||||
@ -761,10 +760,10 @@ TYPED_TEST(CypherMainVisitorTest, NodePattern) {
|
||||
EXPECT_EQ(node->identifier_->name_,
|
||||
CypherMainVisitor::kAnonPrefix + std::to_string(1));
|
||||
EXPECT_FALSE(node->identifier_->user_declared_);
|
||||
EXPECT_THAT(node->labels_, UnorderedElementsAre(
|
||||
ast_generator.db_accessor_->Label("label1"),
|
||||
ast_generator.db_accessor_->Label("label2"),
|
||||
ast_generator.db_accessor_->Label("label3")));
|
||||
EXPECT_THAT(node->labels_,
|
||||
UnorderedElementsAre(ast_generator.db_accessor_.Label("label1"),
|
||||
ast_generator.db_accessor_.Label("label2"),
|
||||
ast_generator.db_accessor_.Label("label3")));
|
||||
std::map<std::pair<std::string, GraphDbTypes::Property>, int64_t> properties;
|
||||
for (auto x : node->properties_) {
|
||||
TypedValue value = LiteralValue(ast_generator.context_, x.second);
|
||||
@ -855,8 +854,8 @@ TYPED_TEST(CypherMainVisitorTest, RelationshipPatternDetails) {
|
||||
EXPECT_EQ(edge->direction_, EdgeAtom::Direction::IN);
|
||||
EXPECT_THAT(
|
||||
edge->edge_types_,
|
||||
UnorderedElementsAre(ast_generator.db_accessor_->EdgeType("type1"),
|
||||
ast_generator.db_accessor_->EdgeType("type2")));
|
||||
UnorderedElementsAre(ast_generator.db_accessor_.EdgeType("type1"),
|
||||
ast_generator.db_accessor_.EdgeType("type2")));
|
||||
std::map<std::pair<std::string, GraphDbTypes::Property>, int64_t> properties;
|
||||
for (auto x : edge->properties_) {
|
||||
TypedValue value = LiteralValue(ast_generator.context_, x.second);
|
||||
@ -994,7 +993,7 @@ TYPED_TEST(CypherMainVisitorTest,
|
||||
CheckLiteral(ast_generator.context_,
|
||||
edge->properties_[ast_generator.PropPair("prop")], 42);
|
||||
ASSERT_EQ(edge->edge_types_.size(), 1U);
|
||||
auto edge_type = ast_generator.db_accessor_->EdgeType("edge_type");
|
||||
auto edge_type = ast_generator.db_accessor_.EdgeType("edge_type");
|
||||
EXPECT_EQ(edge->edge_types_[0], edge_type);
|
||||
}
|
||||
|
||||
@ -1116,7 +1115,7 @@ TYPED_TEST(CypherMainVisitorTest, Set) {
|
||||
ASSERT_TRUE(identifier1);
|
||||
ASSERT_EQ(identifier1->name_, "a");
|
||||
ASSERT_EQ(set_property->property_lookup_->property_,
|
||||
ast_generator.db_accessor_->Property("x"));
|
||||
ast_generator.db_accessor_.Property("x"));
|
||||
auto *identifier2 = dynamic_cast<Identifier *>(set_property->expression_);
|
||||
ASSERT_EQ(identifier2->name_, "b");
|
||||
}
|
||||
@ -1151,8 +1150,8 @@ TYPED_TEST(CypherMainVisitorTest, Set) {
|
||||
ASSERT_TRUE(set_labels->identifier_);
|
||||
ASSERT_EQ(set_labels->identifier_->name_, "g");
|
||||
ASSERT_THAT(set_labels->labels_,
|
||||
UnorderedElementsAre(ast_generator.db_accessor_->Label("h"),
|
||||
ast_generator.db_accessor_->Label("i")));
|
||||
UnorderedElementsAre(ast_generator.db_accessor_.Label("h"),
|
||||
ast_generator.db_accessor_.Label("i")));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1170,7 +1169,7 @@ TYPED_TEST(CypherMainVisitorTest, Remove) {
|
||||
ASSERT_TRUE(identifier1);
|
||||
ASSERT_EQ(identifier1->name_, "a");
|
||||
ASSERT_EQ(remove_property->property_lookup_->property_,
|
||||
ast_generator.db_accessor_->Property("x"));
|
||||
ast_generator.db_accessor_.Property("x"));
|
||||
}
|
||||
{
|
||||
auto *remove_labels = dynamic_cast<RemoveLabels *>(query->clauses_[1]);
|
||||
@ -1178,8 +1177,8 @@ TYPED_TEST(CypherMainVisitorTest, Remove) {
|
||||
ASSERT_TRUE(remove_labels->identifier_);
|
||||
ASSERT_EQ(remove_labels->identifier_->name_, "g");
|
||||
ASSERT_THAT(remove_labels->labels_,
|
||||
UnorderedElementsAre(ast_generator.db_accessor_->Label("h"),
|
||||
ast_generator.db_accessor_->Label("i")));
|
||||
UnorderedElementsAre(ast_generator.db_accessor_.Label("h"),
|
||||
ast_generator.db_accessor_.Label("i")));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1356,9 +1355,9 @@ TYPED_TEST(CypherMainVisitorTest, CreateIndex) {
|
||||
ASSERT_EQ(query->clauses_.size(), 1U);
|
||||
auto *create_index = dynamic_cast<CreateIndex *>(query->clauses_[0]);
|
||||
ASSERT_TRUE(create_index);
|
||||
ASSERT_EQ(create_index->label_, ast_generator.db_accessor_->Label("mirko"));
|
||||
ASSERT_EQ(create_index->label_, ast_generator.db_accessor_.Label("mirko"));
|
||||
ASSERT_EQ(create_index->property_,
|
||||
ast_generator.db_accessor_->Property("slavko"));
|
||||
ast_generator.db_accessor_.Property("slavko"));
|
||||
}
|
||||
|
||||
TYPED_TEST(CypherMainVisitorTest, ReturnAll) {
|
||||
@ -1392,8 +1391,8 @@ TYPED_TEST(CypherMainVisitorTest, MatchBfsReturn) {
|
||||
EXPECT_EQ(bfs->direction_, EdgeAtom::Direction::OUT);
|
||||
EXPECT_THAT(
|
||||
bfs->edge_types_,
|
||||
UnorderedElementsAre(ast_generator.db_accessor_->EdgeType("type1"),
|
||||
ast_generator.db_accessor_->EdgeType("type2")));
|
||||
UnorderedElementsAre(ast_generator.db_accessor_.EdgeType("type1"),
|
||||
ast_generator.db_accessor_.EdgeType("type2")));
|
||||
EXPECT_EQ(bfs->identifier_->name_, "r");
|
||||
EXPECT_EQ(bfs->inner_edge_->name_, "e");
|
||||
EXPECT_EQ(bfs->inner_node_->name_, "n");
|
||||
@ -1401,4 +1400,4 @@ TYPED_TEST(CypherMainVisitorTest, MatchBfsReturn) {
|
||||
auto *eq = dynamic_cast<EqualOperator *>(bfs->filter_expression_);
|
||||
ASSERT_TRUE(eq);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
@ -1,7 +1,6 @@
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "database/dbms.hpp"
|
||||
#include "database/graph_db_accessor.hpp"
|
||||
#include "database/graph_db_datatypes.hpp"
|
||||
#include "storage/vertex.hpp"
|
||||
@ -13,36 +12,36 @@ using testing::UnorderedElementsAreArray;
|
||||
// Test index does it insert everything uniquely
|
||||
TEST(LabelsIndex, UniqueInsert) {
|
||||
KeyIndex<GraphDbTypes::Label, Vertex> index;
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
tx::Engine engine;
|
||||
auto t1 = engine.Begin();
|
||||
mvcc::VersionList<Vertex> vlist(*t1);
|
||||
t1->Commit();
|
||||
auto t2 = engine.Begin();
|
||||
|
||||
vlist.find(*t2)->labels_.push_back(dba->Label("1"));
|
||||
index.Update(dba->Label("1"), &vlist, vlist.find(*t2));
|
||||
vlist.find(*t2)->labels_.push_back(dba.Label("1"));
|
||||
index.Update(dba.Label("1"), &vlist, vlist.find(*t2));
|
||||
// Try multiple inserts
|
||||
index.Update(dba->Label("1"), &vlist, vlist.find(*t2));
|
||||
index.Update(dba.Label("1"), &vlist, vlist.find(*t2));
|
||||
|
||||
vlist.find(*t2)->labels_.push_back(dba->Label("2"));
|
||||
index.Update(dba->Label("2"), &vlist, vlist.find(*t2));
|
||||
vlist.find(*t2)->labels_.push_back(dba.Label("2"));
|
||||
index.Update(dba.Label("2"), &vlist, vlist.find(*t2));
|
||||
|
||||
vlist.find(*t2)->labels_.push_back(dba->Label("3"));
|
||||
index.Update(dba->Label("3"), &vlist, vlist.find(*t2));
|
||||
vlist.find(*t2)->labels_.push_back(dba.Label("3"));
|
||||
index.Update(dba.Label("3"), &vlist, vlist.find(*t2));
|
||||
t2->Commit();
|
||||
|
||||
EXPECT_EQ(index.Count(dba->Label("1")), 1);
|
||||
EXPECT_EQ(index.Count(dba->Label("2")), 1);
|
||||
EXPECT_EQ(index.Count(dba->Label("3")), 1);
|
||||
EXPECT_EQ(index.Count(dba.Label("1")), 1);
|
||||
EXPECT_EQ(index.Count(dba.Label("2")), 1);
|
||||
EXPECT_EQ(index.Count(dba.Label("3")), 1);
|
||||
}
|
||||
|
||||
// Check if index filters duplicates.
|
||||
TEST(LabelsIndex, UniqueFilter) {
|
||||
Dbms dbms;
|
||||
GraphDb db;
|
||||
KeyIndex<GraphDbTypes::Label, Vertex> index;
|
||||
auto dba = dbms.active();
|
||||
GraphDbAccessor dba(db);
|
||||
tx::Engine engine;
|
||||
|
||||
auto t1 = engine.Begin();
|
||||
@ -53,7 +52,7 @@ TEST(LabelsIndex, UniqueFilter) {
|
||||
auto r1v2 = vlist2.find(*t1);
|
||||
EXPECT_NE(vlist1.find(*t1), nullptr);
|
||||
|
||||
auto label1 = dba->Label("1");
|
||||
auto label1 = dba.Label("1");
|
||||
vlist1.find(*t1)->labels_.push_back(label1);
|
||||
vlist2.find(*t1)->labels_.push_back(label1);
|
||||
index.Update(label1, &vlist1, r1v1);
|
||||
@ -81,8 +80,8 @@ TEST(LabelsIndex, UniqueFilter) {
|
||||
// Delete not anymore relevant recods from index.
|
||||
TEST(LabelsIndex, Refresh) {
|
||||
KeyIndex<GraphDbTypes::Label, Vertex> index;
|
||||
Dbms dbms;
|
||||
auto access = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor access(db);
|
||||
tx::Engine engine;
|
||||
|
||||
// add two vertices to database
|
||||
@ -96,7 +95,7 @@ TEST(LabelsIndex, Refresh) {
|
||||
EXPECT_NE(v1r1, nullptr);
|
||||
EXPECT_NE(v2r1, nullptr);
|
||||
|
||||
auto label = access->Label("label");
|
||||
auto label = access.Label("label");
|
||||
v1r1->labels_.push_back(label);
|
||||
v2r1->labels_.push_back(label);
|
||||
index.Update(label, &vlist1, v1r1);
|
||||
@ -120,11 +119,11 @@ TEST(LabelsIndex, Refresh) {
|
||||
|
||||
// Transaction hasn't ended and so the vertex is not visible.
|
||||
TEST(LabelsIndexDb, AddGetZeroLabels) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto vertex = dba->InsertVertex();
|
||||
vertex.add_label(dba->Label("test"));
|
||||
auto collection = dba->Vertices(dba->Label("test"), false);
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto vertex = dba.InsertVertex();
|
||||
vertex.add_label(dba.Label("test"));
|
||||
auto collection = dba.Vertices(dba.Label("test"), false);
|
||||
std::vector<VertexAccessor> collection_vector(collection.begin(),
|
||||
collection.end());
|
||||
EXPECT_EQ(collection_vector.size(), (size_t)0);
|
||||
@ -133,63 +132,63 @@ TEST(LabelsIndexDb, AddGetZeroLabels) {
|
||||
// Test label index by adding and removing one vertex, and removing label from
|
||||
// another, while the third one with an irrelevant label exists.
|
||||
TEST(LabelsIndexDb, AddGetRemoveLabel) {
|
||||
Dbms dbms;
|
||||
GraphDb db;
|
||||
{
|
||||
auto dba = dbms.active();
|
||||
GraphDbAccessor dba(db);
|
||||
|
||||
auto vertex1 = dba->InsertVertex();
|
||||
vertex1.add_label(dba->Label("test"));
|
||||
auto vertex1 = dba.InsertVertex();
|
||||
vertex1.add_label(dba.Label("test"));
|
||||
|
||||
auto vertex2 = dba->InsertVertex();
|
||||
vertex2.add_label(dba->Label("test2"));
|
||||
auto vertex2 = dba.InsertVertex();
|
||||
vertex2.add_label(dba.Label("test2"));
|
||||
|
||||
auto vertex3 = dba->InsertVertex();
|
||||
vertex3.add_label(dba->Label("test"));
|
||||
auto vertex3 = dba.InsertVertex();
|
||||
vertex3.add_label(dba.Label("test"));
|
||||
|
||||
dba->Commit();
|
||||
dba.Commit();
|
||||
} // Finish transaction.
|
||||
{
|
||||
auto dba = dbms.active();
|
||||
GraphDbAccessor dba(db);
|
||||
|
||||
auto filtered = dba->Vertices(dba->Label("test"), false);
|
||||
auto filtered = dba.Vertices(dba.Label("test"), false);
|
||||
std::vector<VertexAccessor> collection(filtered.begin(), filtered.end());
|
||||
auto vertices = dba->Vertices(false);
|
||||
auto vertices = dba.Vertices(false);
|
||||
|
||||
std::vector<VertexAccessor> expected_collection;
|
||||
for (auto vertex : vertices) {
|
||||
if (vertex.has_label(dba->Label("test"))) {
|
||||
if (vertex.has_label(dba.Label("test"))) {
|
||||
expected_collection.push_back(vertex);
|
||||
} else {
|
||||
EXPECT_TRUE(vertex.has_label(dba->Label("test2")));
|
||||
EXPECT_TRUE(vertex.has_label(dba.Label("test2")));
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_EQ(expected_collection.size(), collection.size());
|
||||
EXPECT_TRUE(collection[0].has_label(dba->Label("test")));
|
||||
EXPECT_TRUE(collection[1].has_label(dba->Label("test")));
|
||||
EXPECT_FALSE(collection[0].has_label(dba->Label("test2")));
|
||||
EXPECT_FALSE(collection[1].has_label(dba->Label("test2")));
|
||||
dba->RemoveVertex(collection[0]); // Remove from database and test if
|
||||
// index won't return it.
|
||||
EXPECT_TRUE(collection[0].has_label(dba.Label("test")));
|
||||
EXPECT_TRUE(collection[1].has_label(dba.Label("test")));
|
||||
EXPECT_FALSE(collection[0].has_label(dba.Label("test2")));
|
||||
EXPECT_FALSE(collection[1].has_label(dba.Label("test2")));
|
||||
dba.RemoveVertex(collection[0]); // Remove from database and test if
|
||||
// index won't return it.
|
||||
|
||||
// Remove label from the vertex and add new label.
|
||||
collection[1].remove_label(dba->Label("test"));
|
||||
collection[1].add_label(dba->Label("test2"));
|
||||
dba->Commit();
|
||||
collection[1].remove_label(dba.Label("test"));
|
||||
collection[1].add_label(dba.Label("test2"));
|
||||
dba.Commit();
|
||||
}
|
||||
{
|
||||
auto dba = dbms.active();
|
||||
GraphDbAccessor dba(db);
|
||||
|
||||
auto filtered = dba->Vertices(dba->Label("test"), false);
|
||||
auto filtered = dba.Vertices(dba.Label("test"), false);
|
||||
std::vector<VertexAccessor> collection(filtered.begin(), filtered.end());
|
||||
auto vertices = dba->Vertices(false);
|
||||
auto vertices = dba.Vertices(false);
|
||||
|
||||
std::vector<VertexAccessor> expected_collection;
|
||||
for (auto vertex : vertices) {
|
||||
if (vertex.has_label(dba->Label("test"))) {
|
||||
if (vertex.has_label(dba.Label("test"))) {
|
||||
expected_collection.push_back(vertex);
|
||||
} else {
|
||||
EXPECT_TRUE(vertex.has_label(dba->Label("test2")));
|
||||
EXPECT_TRUE(vertex.has_label(dba.Label("test2")));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "database/dbms.hpp"
|
||||
#include "database/graph_db.hpp"
|
||||
#include "database/graph_db_accessor.hpp"
|
||||
#include "database/graph_db_datatypes.hpp"
|
||||
#include "database/indexes/label_property_index.hpp"
|
||||
|
||||
@ -10,12 +10,12 @@
|
||||
class LabelPropertyIndexComplexTest : public ::testing::Test {
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
auto accessor = dbms.active();
|
||||
GraphDbAccessor accessor(db_);
|
||||
|
||||
label = accessor->Label("label");
|
||||
property = accessor->Property("property");
|
||||
label2 = accessor->Label("label2");
|
||||
property2 = accessor->Property("property2");
|
||||
label = accessor.Label("label");
|
||||
property = accessor.Property("property");
|
||||
label2 = accessor.Label("label2");
|
||||
property2 = accessor.Property("property2");
|
||||
|
||||
key = new LabelPropertyIndex::Key(label, property);
|
||||
EXPECT_EQ(index.CreateIndex(*key), true);
|
||||
@ -39,7 +39,7 @@ class LabelPropertyIndexComplexTest : public ::testing::Test {
|
||||
}
|
||||
|
||||
public:
|
||||
Dbms dbms;
|
||||
GraphDb db_;
|
||||
LabelPropertyIndex index;
|
||||
LabelPropertyIndex::Key *key;
|
||||
|
||||
@ -56,20 +56,20 @@ class LabelPropertyIndexComplexTest : public ::testing::Test {
|
||||
};
|
||||
|
||||
TEST(LabelPropertyIndex, CreateIndex) {
|
||||
Dbms dbms;
|
||||
auto accessor = dbms.active();
|
||||
LabelPropertyIndex::Key key(accessor->Label("test"),
|
||||
accessor->Property("test2"));
|
||||
GraphDb db;
|
||||
GraphDbAccessor accessor(db);
|
||||
LabelPropertyIndex::Key key(accessor.Label("test"),
|
||||
accessor.Property("test2"));
|
||||
LabelPropertyIndex index;
|
||||
EXPECT_EQ(index.CreateIndex(key), true);
|
||||
EXPECT_EQ(index.CreateIndex(key), false);
|
||||
}
|
||||
|
||||
TEST(LabelPropertyIndex, IndexExistance) {
|
||||
Dbms dbms;
|
||||
auto accessor = dbms.active();
|
||||
LabelPropertyIndex::Key key(accessor->Label("test"),
|
||||
accessor->Property("test2"));
|
||||
GraphDb db;
|
||||
GraphDbAccessor accessor(db);
|
||||
LabelPropertyIndex::Key key(accessor.Label("test"),
|
||||
accessor.Property("test2"));
|
||||
LabelPropertyIndex index;
|
||||
EXPECT_EQ(index.CreateIndex(key), true);
|
||||
// Index doesn't exist - and can't be used untill it's been notified as built.
|
||||
@ -79,10 +79,10 @@ TEST(LabelPropertyIndex, IndexExistance) {
|
||||
}
|
||||
|
||||
TEST(LabelPropertyIndex, Count) {
|
||||
Dbms dbms;
|
||||
auto accessor = dbms.active();
|
||||
auto label = accessor->Label("label");
|
||||
auto property = accessor->Property("property");
|
||||
GraphDb db;
|
||||
GraphDbAccessor accessor(db);
|
||||
auto label = accessor.Label("label");
|
||||
auto property = accessor.Property("property");
|
||||
LabelPropertyIndex::Key key(label, property);
|
||||
LabelPropertyIndex index;
|
||||
::testing::FLAGS_gtest_death_test_style = "threadsafe";
|
||||
|
@ -1,6 +1,5 @@
|
||||
#include <glog/logging.h>
|
||||
#include "communication/result_stream_faker.hpp"
|
||||
#include "database/dbms.hpp"
|
||||
#include "query/exceptions.hpp"
|
||||
#include "query/interpreter.hpp"
|
||||
|
||||
@ -10,25 +9,25 @@ DECLARE_int32(query_execution_time_sec);
|
||||
|
||||
TEST(TransactionTimeout, TransactionTimeout) {
|
||||
FLAGS_query_execution_time_sec = 3;
|
||||
Dbms dbms;
|
||||
GraphDb db;
|
||||
query::Interpreter interpreter;
|
||||
{
|
||||
ResultStreamFaker stream;
|
||||
auto dba1 = dbms.active();
|
||||
interpreter.Interpret("MATCH (n) RETURN n", *dba1, stream, {}, false);
|
||||
GraphDbAccessor dba(db);
|
||||
interpreter.Interpret("MATCH (n) RETURN n", dba, stream, {}, false);
|
||||
}
|
||||
{
|
||||
ResultStreamFaker stream;
|
||||
auto dba2 = dbms.active();
|
||||
GraphDbAccessor dba(db);
|
||||
std::this_thread::sleep_for(std::chrono::seconds(5));
|
||||
ASSERT_THROW(
|
||||
interpreter.Interpret("MATCH (n) RETURN n", *dba2, stream, {}, false),
|
||||
interpreter.Interpret("MATCH (n) RETURN n", dba, stream, {}, false),
|
||||
query::HintedAbortError);
|
||||
}
|
||||
{
|
||||
ResultStreamFaker stream;
|
||||
auto dba3 = dbms.active();
|
||||
interpreter.Interpret("MATCH (n) RETURN n", *dba3, stream, {}, false);
|
||||
GraphDbAccessor dba(db);
|
||||
interpreter.Interpret("MATCH (n) RETURN n", dba, stream, {}, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,101 +0,0 @@
|
||||
#include <experimental/filesystem>
|
||||
|
||||
#include "gflags/gflags.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "database/dbms.hpp"
|
||||
|
||||
DECLARE_bool(recovery_on_startup);
|
||||
DECLARE_string(snapshot_directory);
|
||||
DECLARE_int32(snapshot_cycle_sec);
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
char tmp[] = "XXXXXX";
|
||||
const fs::path SNAPSHOTS_DBMS_RECOVERY_ALL_DB = mkdtemp(tmp);
|
||||
const fs::path SNAPSHOTS_DBMS_RECOVERY_DEFAULT_DB_DIR =
|
||||
SNAPSHOTS_DBMS_RECOVERY_ALL_DB / "default";
|
||||
|
||||
std::vector<fs::path> GetFilesFromDir(
|
||||
const std::string &snapshots_default_db_dir) {
|
||||
std::vector<fs::path> files;
|
||||
for (auto &file : fs::directory_iterator(snapshots_default_db_dir))
|
||||
files.push_back(file.path());
|
||||
return files;
|
||||
}
|
||||
|
||||
void CleanDbDir() {
|
||||
if (!fs::exists(SNAPSHOTS_DBMS_RECOVERY_DEFAULT_DB_DIR)) return;
|
||||
std::vector<fs::path> files =
|
||||
GetFilesFromDir(SNAPSHOTS_DBMS_RECOVERY_DEFAULT_DB_DIR);
|
||||
for (auto file : files) fs::remove(file);
|
||||
}
|
||||
|
||||
class DbmsRecoveryTest : public ::testing::Test {
|
||||
protected:
|
||||
virtual void TearDown() { CleanDbDir(); }
|
||||
|
||||
virtual void SetUp() {
|
||||
CleanDbDir();
|
||||
FLAGS_snapshot_directory = SNAPSHOTS_DBMS_RECOVERY_ALL_DB;
|
||||
FLAGS_snapshot_cycle_sec = -1;
|
||||
}
|
||||
};
|
||||
|
||||
void CreateSnapshot() {
|
||||
FLAGS_snapshot_recover_on_startup = false;
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
|
||||
// setup (v1) - [:likes] -> (v2) <- [:hates] - (v3)
|
||||
auto va1 = dba->InsertVertex();
|
||||
auto va2 = dba->InsertVertex();
|
||||
dba->InsertEdge(va1, va2, dba->EdgeType("likes"));
|
||||
auto va3 = dba->InsertVertex();
|
||||
dba->InsertEdge(va3, va2, dba->EdgeType("hates"));
|
||||
dba->AdvanceCommand();
|
||||
|
||||
Snapshooter snapshooter;
|
||||
EXPECT_EQ(snapshooter.MakeSnapshot(*dba.get(),
|
||||
SNAPSHOTS_DBMS_RECOVERY_DEFAULT_DB_DIR, 1),
|
||||
true);
|
||||
}
|
||||
|
||||
void RecoverDbms() {
|
||||
FLAGS_snapshot_recover_on_startup = true;
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
|
||||
std::vector<VertexAccessor> vertices;
|
||||
std::vector<EdgeAccessor> edges;
|
||||
|
||||
int vertex_count = 0;
|
||||
for (auto const &vertex : dba->Vertices(false)) {
|
||||
vertices.push_back(vertex);
|
||||
vertex_count++;
|
||||
}
|
||||
EXPECT_EQ(vertex_count, 3);
|
||||
|
||||
int edge_count = 0;
|
||||
for (auto const &edge : dba->Edges(false)) {
|
||||
EXPECT_NE(vertices.end(),
|
||||
std::find(vertices.begin(), vertices.end(), edge.to()));
|
||||
EXPECT_NE(vertices.end(),
|
||||
std::find(vertices.begin(), vertices.end(), edge.from()));
|
||||
edges.push_back(edge);
|
||||
edge_count++;
|
||||
}
|
||||
ASSERT_EQ(edge_count, 2);
|
||||
EXPECT_EQ(edges[0].to() == edges[1].to(), true);
|
||||
EXPECT_EQ(edges[0].from() == edges[1].from(), false);
|
||||
}
|
||||
|
||||
TEST_F(DbmsRecoveryTest, TestDbmsRecovery) {
|
||||
CreateSnapshot();
|
||||
RecoverDbms();
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
@ -11,7 +11,7 @@ DECLARE_int32(gc_cycle_sec);
|
||||
|
||||
TEST(GraphDbTest, GarbageCollectIndices) {
|
||||
FLAGS_gc_cycle_sec = -1;
|
||||
GraphDb graph_db{"default", fs::path()};
|
||||
GraphDb graph_db;
|
||||
std::unique_ptr<GraphDbAccessor> dba =
|
||||
std::make_unique<GraphDbAccessor>(graph_db);
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
#include <experimental/optional>
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "database/dbms.hpp"
|
||||
#include "database/graph_db.hpp"
|
||||
#include "database/graph_db_accessor.hpp"
|
||||
|
||||
@ -13,90 +12,87 @@ auto Count(TIterable iterable) {
|
||||
return std::distance(iterable.begin(), iterable.end());
|
||||
}
|
||||
|
||||
TEST(GraphDbAccessorTest, DbmsCreateDefault) {
|
||||
Dbms dbms;
|
||||
auto accessor = dbms.active();
|
||||
EXPECT_EQ(accessor->name(), "default");
|
||||
}
|
||||
|
||||
TEST(GraphDbAccessorTest, InsertVertex) {
|
||||
Dbms dbms;
|
||||
auto accessor = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor accessor(db);
|
||||
|
||||
EXPECT_EQ(Count(accessor->Vertices(false)), 0);
|
||||
EXPECT_EQ(Count(accessor.Vertices(false)), 0);
|
||||
|
||||
accessor->InsertVertex();
|
||||
EXPECT_EQ(Count(accessor->Vertices(false)), 0);
|
||||
EXPECT_EQ(Count(accessor->Vertices(true)), 1);
|
||||
accessor->AdvanceCommand();
|
||||
EXPECT_EQ(Count(accessor->Vertices(false)), 1);
|
||||
accessor.InsertVertex();
|
||||
EXPECT_EQ(Count(accessor.Vertices(false)), 0);
|
||||
EXPECT_EQ(Count(accessor.Vertices(true)), 1);
|
||||
accessor.AdvanceCommand();
|
||||
EXPECT_EQ(Count(accessor.Vertices(false)), 1);
|
||||
|
||||
accessor->InsertVertex();
|
||||
EXPECT_EQ(Count(accessor->Vertices(false)), 1);
|
||||
EXPECT_EQ(Count(accessor->Vertices(true)), 2);
|
||||
accessor->AdvanceCommand();
|
||||
EXPECT_EQ(Count(accessor->Vertices(false)), 2);
|
||||
accessor.InsertVertex();
|
||||
EXPECT_EQ(Count(accessor.Vertices(false)), 1);
|
||||
EXPECT_EQ(Count(accessor.Vertices(true)), 2);
|
||||
accessor.AdvanceCommand();
|
||||
EXPECT_EQ(Count(accessor.Vertices(false)), 2);
|
||||
}
|
||||
|
||||
TEST(GraphDbAccessorTest, RemoveVertexSameTransaction) {
|
||||
Dbms dbms;
|
||||
auto accessor = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor accessor(db);
|
||||
|
||||
EXPECT_EQ(Count(accessor->Vertices(false)), 0);
|
||||
EXPECT_EQ(Count(accessor.Vertices(false)), 0);
|
||||
|
||||
auto va1 = accessor->InsertVertex();
|
||||
accessor->AdvanceCommand();
|
||||
EXPECT_EQ(Count(accessor->Vertices(false)), 1);
|
||||
auto va1 = accessor.InsertVertex();
|
||||
accessor.AdvanceCommand();
|
||||
EXPECT_EQ(Count(accessor.Vertices(false)), 1);
|
||||
|
||||
EXPECT_TRUE(accessor->RemoveVertex(va1));
|
||||
EXPECT_EQ(Count(accessor->Vertices(false)), 1);
|
||||
EXPECT_EQ(Count(accessor->Vertices(true)), 0);
|
||||
accessor->AdvanceCommand();
|
||||
EXPECT_EQ(Count(accessor->Vertices(false)), 0);
|
||||
EXPECT_EQ(Count(accessor->Vertices(true)), 0);
|
||||
EXPECT_TRUE(accessor.RemoveVertex(va1));
|
||||
EXPECT_EQ(Count(accessor.Vertices(false)), 1);
|
||||
EXPECT_EQ(Count(accessor.Vertices(true)), 0);
|
||||
accessor.AdvanceCommand();
|
||||
EXPECT_EQ(Count(accessor.Vertices(false)), 0);
|
||||
EXPECT_EQ(Count(accessor.Vertices(true)), 0);
|
||||
}
|
||||
|
||||
TEST(GraphDbAccessorTest, RemoveVertexDifferentTransaction) {
|
||||
Dbms dbms;
|
||||
|
||||
GraphDb db;
|
||||
// first transaction creates a vertex
|
||||
auto accessor1 = dbms.active();
|
||||
accessor1->InsertVertex();
|
||||
accessor1->Commit();
|
||||
|
||||
{
|
||||
GraphDbAccessor accessor(db);
|
||||
accessor.InsertVertex();
|
||||
accessor.Commit();
|
||||
}
|
||||
// second transaction checks that it sees it, and deletes it
|
||||
auto accessor2 = dbms.active();
|
||||
EXPECT_EQ(Count(accessor2->Vertices(false)), 1);
|
||||
EXPECT_EQ(Count(accessor2->Vertices(true)), 1);
|
||||
for (auto vertex_accessor : accessor2->Vertices(false))
|
||||
accessor2->RemoveVertex(vertex_accessor);
|
||||
accessor2->Commit();
|
||||
|
||||
{
|
||||
GraphDbAccessor accessor(db);
|
||||
EXPECT_EQ(Count(accessor.Vertices(false)), 1);
|
||||
EXPECT_EQ(Count(accessor.Vertices(true)), 1);
|
||||
for (auto vertex_accessor : accessor.Vertices(false))
|
||||
accessor.RemoveVertex(vertex_accessor);
|
||||
accessor.Commit();
|
||||
}
|
||||
// third transaction checks that it does not see the vertex
|
||||
auto accessor3 = dbms.active();
|
||||
EXPECT_EQ(Count(accessor3->Vertices(false)), 0);
|
||||
EXPECT_EQ(Count(accessor3->Vertices(true)), 0);
|
||||
{
|
||||
GraphDbAccessor accessor(db);
|
||||
EXPECT_EQ(Count(accessor.Vertices(false)), 0);
|
||||
EXPECT_EQ(Count(accessor.Vertices(true)), 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(GraphDbAccessorTest, InsertEdge) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
|
||||
auto va1 = dba->InsertVertex();
|
||||
auto va2 = dba->InsertVertex();
|
||||
dba->AdvanceCommand();
|
||||
auto va1 = dba.InsertVertex();
|
||||
auto va2 = dba.InsertVertex();
|
||||
dba.AdvanceCommand();
|
||||
EXPECT_EQ(va1.in_degree(), 0);
|
||||
EXPECT_EQ(va1.out_degree(), 0);
|
||||
EXPECT_EQ(va2.in_degree(), 0);
|
||||
EXPECT_EQ(va2.out_degree(), 0);
|
||||
|
||||
// setup (v1) - [:likes] -> (v2)
|
||||
dba->InsertEdge(va1, va2, dba->EdgeType("likes"));
|
||||
EXPECT_EQ(Count(dba->Edges(false)), 0);
|
||||
EXPECT_EQ(Count(dba->Edges(true)), 1);
|
||||
dba->AdvanceCommand();
|
||||
EXPECT_EQ(Count(dba->Edges(false)), 1);
|
||||
EXPECT_EQ(Count(dba->Edges(true)), 1);
|
||||
dba.InsertEdge(va1, va2, dba.EdgeType("likes"));
|
||||
EXPECT_EQ(Count(dba.Edges(false)), 0);
|
||||
EXPECT_EQ(Count(dba.Edges(true)), 1);
|
||||
dba.AdvanceCommand();
|
||||
EXPECT_EQ(Count(dba.Edges(false)), 1);
|
||||
EXPECT_EQ(Count(dba.Edges(true)), 1);
|
||||
EXPECT_EQ(va1.out().begin()->to(), va2);
|
||||
EXPECT_EQ(va2.in().begin()->from(), va1);
|
||||
EXPECT_EQ(va1.in_degree(), 0);
|
||||
@ -105,12 +101,12 @@ TEST(GraphDbAccessorTest, InsertEdge) {
|
||||
EXPECT_EQ(va2.out_degree(), 0);
|
||||
|
||||
// setup (v1) - [:likes] -> (v2) <- [:hates] - (v3)
|
||||
auto va3 = dba->InsertVertex();
|
||||
dba->InsertEdge(va3, va2, dba->EdgeType("hates"));
|
||||
EXPECT_EQ(Count(dba->Edges(false)), 1);
|
||||
EXPECT_EQ(Count(dba->Edges(true)), 2);
|
||||
dba->AdvanceCommand();
|
||||
EXPECT_EQ(Count(dba->Edges(false)), 2);
|
||||
auto va3 = dba.InsertVertex();
|
||||
dba.InsertEdge(va3, va2, dba.EdgeType("hates"));
|
||||
EXPECT_EQ(Count(dba.Edges(false)), 1);
|
||||
EXPECT_EQ(Count(dba.Edges(true)), 2);
|
||||
dba.AdvanceCommand();
|
||||
EXPECT_EQ(Count(dba.Edges(false)), 2);
|
||||
EXPECT_EQ(va3.out().begin()->to(), va2);
|
||||
EXPECT_EQ(va1.in_degree(), 0);
|
||||
EXPECT_EQ(va1.out_degree(), 1);
|
||||
@ -121,38 +117,38 @@ TEST(GraphDbAccessorTest, InsertEdge) {
|
||||
}
|
||||
|
||||
TEST(GraphDbAccessorTest, RemoveEdge) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
|
||||
// setup (v1) - [:likes] -> (v2) <- [:hates] - (v3)
|
||||
auto va1 = dba->InsertVertex();
|
||||
auto va2 = dba->InsertVertex();
|
||||
auto va3 = dba->InsertVertex();
|
||||
dba->InsertEdge(va1, va2, dba->EdgeType("likes"));
|
||||
dba->InsertEdge(va3, va2, dba->EdgeType("hates"));
|
||||
dba->AdvanceCommand();
|
||||
EXPECT_EQ(Count(dba->Edges(false)), 2);
|
||||
EXPECT_EQ(Count(dba->Edges(true)), 2);
|
||||
auto va1 = dba.InsertVertex();
|
||||
auto va2 = dba.InsertVertex();
|
||||
auto va3 = dba.InsertVertex();
|
||||
dba.InsertEdge(va1, va2, dba.EdgeType("likes"));
|
||||
dba.InsertEdge(va3, va2, dba.EdgeType("hates"));
|
||||
dba.AdvanceCommand();
|
||||
EXPECT_EQ(Count(dba.Edges(false)), 2);
|
||||
EXPECT_EQ(Count(dba.Edges(true)), 2);
|
||||
|
||||
// remove all [:hates] edges
|
||||
for (auto edge : dba->Edges(false))
|
||||
if (edge.EdgeType() == dba->EdgeType("hates")) dba->RemoveEdge(edge);
|
||||
EXPECT_EQ(Count(dba->Edges(false)), 2);
|
||||
EXPECT_EQ(Count(dba->Edges(true)), 1);
|
||||
for (auto edge : dba.Edges(false))
|
||||
if (edge.EdgeType() == dba.EdgeType("hates")) dba.RemoveEdge(edge);
|
||||
EXPECT_EQ(Count(dba.Edges(false)), 2);
|
||||
EXPECT_EQ(Count(dba.Edges(true)), 1);
|
||||
|
||||
// current state: (v1) - [:likes] -> (v2), (v3)
|
||||
dba->AdvanceCommand();
|
||||
EXPECT_EQ(Count(dba->Edges(false)), 1);
|
||||
EXPECT_EQ(Count(dba->Edges(true)), 1);
|
||||
EXPECT_EQ(Count(dba->Vertices(false)), 3);
|
||||
EXPECT_EQ(Count(dba->Vertices(true)), 3);
|
||||
for (auto edge : dba->Edges(false)) {
|
||||
EXPECT_EQ(edge.EdgeType(), dba->EdgeType("likes"));
|
||||
dba.AdvanceCommand();
|
||||
EXPECT_EQ(Count(dba.Edges(false)), 1);
|
||||
EXPECT_EQ(Count(dba.Edges(true)), 1);
|
||||
EXPECT_EQ(Count(dba.Vertices(false)), 3);
|
||||
EXPECT_EQ(Count(dba.Vertices(true)), 3);
|
||||
for (auto edge : dba.Edges(false)) {
|
||||
EXPECT_EQ(edge.EdgeType(), dba.EdgeType("likes"));
|
||||
auto v1 = edge.from();
|
||||
auto v2 = edge.to();
|
||||
|
||||
// ensure correct connectivity for all the vertices
|
||||
for (auto vertex : dba->Vertices(false)) {
|
||||
for (auto vertex : dba.Vertices(false)) {
|
||||
if (vertex == v1) {
|
||||
EXPECT_EQ(vertex.in_degree(), 0);
|
||||
EXPECT_EQ(vertex.out_degree(), 1);
|
||||
@ -168,188 +164,188 @@ TEST(GraphDbAccessorTest, RemoveEdge) {
|
||||
}
|
||||
|
||||
TEST(GraphDbAccessorTest, DetachRemoveVertex) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
|
||||
// setup (v0)- []->(v1)<-[]-(v2)<-[]-(v3)
|
||||
std::vector<VertexAccessor> vertices;
|
||||
for (int i = 0; i < 4; ++i) vertices.emplace_back(dba->InsertVertex());
|
||||
for (int i = 0; i < 4; ++i) vertices.emplace_back(dba.InsertVertex());
|
||||
|
||||
auto edge_type = dba->EdgeType("type");
|
||||
dba->InsertEdge(vertices[0], vertices[1], edge_type);
|
||||
dba->InsertEdge(vertices[2], vertices[1], edge_type);
|
||||
dba->InsertEdge(vertices[3], vertices[2], edge_type);
|
||||
auto edge_type = dba.EdgeType("type");
|
||||
dba.InsertEdge(vertices[0], vertices[1], edge_type);
|
||||
dba.InsertEdge(vertices[2], vertices[1], edge_type);
|
||||
dba.InsertEdge(vertices[3], vertices[2], edge_type);
|
||||
|
||||
dba->AdvanceCommand();
|
||||
dba.AdvanceCommand();
|
||||
for (auto &vertex : vertices) vertex.Reconstruct();
|
||||
|
||||
// ensure that plain remove does NOT work
|
||||
EXPECT_EQ(Count(dba->Vertices(false)), 4);
|
||||
EXPECT_EQ(Count(dba->Edges(false)), 3);
|
||||
EXPECT_FALSE(dba->RemoveVertex(vertices[0]));
|
||||
EXPECT_FALSE(dba->RemoveVertex(vertices[1]));
|
||||
EXPECT_FALSE(dba->RemoveVertex(vertices[2]));
|
||||
EXPECT_EQ(Count(dba->Vertices(false)), 4);
|
||||
EXPECT_EQ(Count(dba->Edges(false)), 3);
|
||||
EXPECT_EQ(Count(dba.Vertices(false)), 4);
|
||||
EXPECT_EQ(Count(dba.Edges(false)), 3);
|
||||
EXPECT_FALSE(dba.RemoveVertex(vertices[0]));
|
||||
EXPECT_FALSE(dba.RemoveVertex(vertices[1]));
|
||||
EXPECT_FALSE(dba.RemoveVertex(vertices[2]));
|
||||
EXPECT_EQ(Count(dba.Vertices(false)), 4);
|
||||
EXPECT_EQ(Count(dba.Edges(false)), 3);
|
||||
|
||||
dba->DetachRemoveVertex(vertices[2]);
|
||||
EXPECT_EQ(Count(dba->Vertices(false)), 4);
|
||||
EXPECT_EQ(Count(dba->Vertices(true)), 3);
|
||||
EXPECT_EQ(Count(dba->Edges(false)), 3);
|
||||
EXPECT_EQ(Count(dba->Edges(true)), 1);
|
||||
dba->AdvanceCommand();
|
||||
dba.DetachRemoveVertex(vertices[2]);
|
||||
EXPECT_EQ(Count(dba.Vertices(false)), 4);
|
||||
EXPECT_EQ(Count(dba.Vertices(true)), 3);
|
||||
EXPECT_EQ(Count(dba.Edges(false)), 3);
|
||||
EXPECT_EQ(Count(dba.Edges(true)), 1);
|
||||
dba.AdvanceCommand();
|
||||
for (auto &vertex : vertices) vertex.Reconstruct();
|
||||
|
||||
EXPECT_EQ(Count(dba->Vertices(false)), 3);
|
||||
EXPECT_EQ(Count(dba->Edges(false)), 1);
|
||||
EXPECT_TRUE(dba->RemoveVertex(vertices[3]));
|
||||
EXPECT_EQ(Count(dba->Vertices(true)), 2);
|
||||
EXPECT_EQ(Count(dba->Vertices(false)), 3);
|
||||
dba->AdvanceCommand();
|
||||
EXPECT_EQ(Count(dba.Vertices(false)), 3);
|
||||
EXPECT_EQ(Count(dba.Edges(false)), 1);
|
||||
EXPECT_TRUE(dba.RemoveVertex(vertices[3]));
|
||||
EXPECT_EQ(Count(dba.Vertices(true)), 2);
|
||||
EXPECT_EQ(Count(dba.Vertices(false)), 3);
|
||||
dba.AdvanceCommand();
|
||||
for (auto &vertex : vertices) vertex.Reconstruct();
|
||||
|
||||
EXPECT_EQ(Count(dba->Vertices(false)), 2);
|
||||
EXPECT_EQ(Count(dba->Edges(false)), 1);
|
||||
for (auto va : dba->Vertices(false)) EXPECT_FALSE(dba->RemoveVertex(va));
|
||||
dba->AdvanceCommand();
|
||||
EXPECT_EQ(Count(dba.Vertices(false)), 2);
|
||||
EXPECT_EQ(Count(dba.Edges(false)), 1);
|
||||
for (auto va : dba.Vertices(false)) EXPECT_FALSE(dba.RemoveVertex(va));
|
||||
dba.AdvanceCommand();
|
||||
for (auto &vertex : vertices) vertex.Reconstruct();
|
||||
|
||||
EXPECT_EQ(Count(dba->Vertices(false)), 2);
|
||||
EXPECT_EQ(Count(dba->Edges(false)), 1);
|
||||
for (auto va : dba->Vertices(false)) {
|
||||
EXPECT_FALSE(dba->RemoveVertex(va));
|
||||
dba->DetachRemoveVertex(va);
|
||||
EXPECT_EQ(Count(dba.Vertices(false)), 2);
|
||||
EXPECT_EQ(Count(dba.Edges(false)), 1);
|
||||
for (auto va : dba.Vertices(false)) {
|
||||
EXPECT_FALSE(dba.RemoveVertex(va));
|
||||
dba.DetachRemoveVertex(va);
|
||||
break;
|
||||
}
|
||||
EXPECT_EQ(Count(dba->Vertices(true)), 1);
|
||||
EXPECT_EQ(Count(dba->Vertices(false)), 2);
|
||||
dba->AdvanceCommand();
|
||||
EXPECT_EQ(Count(dba.Vertices(true)), 1);
|
||||
EXPECT_EQ(Count(dba.Vertices(false)), 2);
|
||||
dba.AdvanceCommand();
|
||||
for (auto &vertex : vertices) vertex.Reconstruct();
|
||||
|
||||
EXPECT_EQ(Count(dba->Vertices(false)), 1);
|
||||
EXPECT_EQ(Count(dba->Edges(false)), 0);
|
||||
EXPECT_EQ(Count(dba.Vertices(false)), 1);
|
||||
EXPECT_EQ(Count(dba.Edges(false)), 0);
|
||||
|
||||
// remove the last vertex, it has no connections
|
||||
// so that should work
|
||||
for (auto va : dba->Vertices(false)) EXPECT_TRUE(dba->RemoveVertex(va));
|
||||
dba->AdvanceCommand();
|
||||
for (auto va : dba.Vertices(false)) EXPECT_TRUE(dba.RemoveVertex(va));
|
||||
dba.AdvanceCommand();
|
||||
|
||||
EXPECT_EQ(Count(dba->Vertices(false)), 0);
|
||||
EXPECT_EQ(Count(dba->Edges(false)), 0);
|
||||
EXPECT_EQ(Count(dba.Vertices(false)), 0);
|
||||
EXPECT_EQ(Count(dba.Edges(false)), 0);
|
||||
}
|
||||
|
||||
TEST(GraphDbAccessorTest, DetachRemoveVertexMultiple) {
|
||||
// This test checks that we can detach remove the
|
||||
// same vertex / edge multiple times
|
||||
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
|
||||
// setup: make a fully connected N graph
|
||||
// with cycles too!
|
||||
int N = 7;
|
||||
std::vector<VertexAccessor> vertices;
|
||||
auto edge_type = dba->EdgeType("edge");
|
||||
for (int i = 0; i < N; ++i) vertices.emplace_back(dba->InsertVertex());
|
||||
auto edge_type = dba.EdgeType("edge");
|
||||
for (int i = 0; i < N; ++i) vertices.emplace_back(dba.InsertVertex());
|
||||
for (int j = 0; j < N; ++j)
|
||||
for (int k = 0; k < N; ++k)
|
||||
dba->InsertEdge(vertices[j], vertices[k], edge_type);
|
||||
dba.InsertEdge(vertices[j], vertices[k], edge_type);
|
||||
|
||||
dba->AdvanceCommand();
|
||||
dba.AdvanceCommand();
|
||||
for (auto &vertex : vertices) vertex.Reconstruct();
|
||||
|
||||
EXPECT_EQ(Count(dba->Vertices(false)), N);
|
||||
EXPECT_EQ(Count(dba->Edges(false)), N * N);
|
||||
EXPECT_EQ(Count(dba.Vertices(false)), N);
|
||||
EXPECT_EQ(Count(dba.Edges(false)), N * N);
|
||||
|
||||
// detach delete one edge
|
||||
dba->DetachRemoveVertex(vertices[0]);
|
||||
dba->AdvanceCommand();
|
||||
dba.DetachRemoveVertex(vertices[0]);
|
||||
dba.AdvanceCommand();
|
||||
for (auto &vertex : vertices) vertex.Reconstruct();
|
||||
EXPECT_EQ(Count(dba->Vertices(false)), N - 1);
|
||||
EXPECT_EQ(Count(dba->Edges(false)), (N - 1) * (N - 1));
|
||||
EXPECT_EQ(Count(dba.Vertices(false)), N - 1);
|
||||
EXPECT_EQ(Count(dba.Edges(false)), (N - 1) * (N - 1));
|
||||
|
||||
// detach delete two neighboring edges
|
||||
dba->DetachRemoveVertex(vertices[1]);
|
||||
dba->DetachRemoveVertex(vertices[2]);
|
||||
dba->AdvanceCommand();
|
||||
dba.DetachRemoveVertex(vertices[1]);
|
||||
dba.DetachRemoveVertex(vertices[2]);
|
||||
dba.AdvanceCommand();
|
||||
for (auto &vertex : vertices) vertex.Reconstruct();
|
||||
EXPECT_EQ(Count(dba->Vertices(false)), N - 3);
|
||||
EXPECT_EQ(Count(dba->Edges(false)), (N - 3) * (N - 3));
|
||||
EXPECT_EQ(Count(dba.Vertices(false)), N - 3);
|
||||
EXPECT_EQ(Count(dba.Edges(false)), (N - 3) * (N - 3));
|
||||
|
||||
// detach delete everything, buwahahahaha
|
||||
for (int l = 3; l < N; ++l) dba->DetachRemoveVertex(vertices[l]);
|
||||
dba->AdvanceCommand();
|
||||
for (int l = 3; l < N; ++l) dba.DetachRemoveVertex(vertices[l]);
|
||||
dba.AdvanceCommand();
|
||||
for (auto &vertex : vertices) vertex.Reconstruct();
|
||||
EXPECT_EQ(Count(dba->Vertices(false)), 0);
|
||||
EXPECT_EQ(Count(dba->Edges(false)), 0);
|
||||
EXPECT_EQ(Count(dba.Vertices(false)), 0);
|
||||
EXPECT_EQ(Count(dba.Edges(false)), 0);
|
||||
}
|
||||
|
||||
TEST(GraphDbAccessorTest, Labels) {
|
||||
Dbms dbms;
|
||||
auto dba1 = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
|
||||
GraphDbTypes::Label label_friend = dba1->Label("friend");
|
||||
EXPECT_EQ(label_friend, dba1->Label("friend"));
|
||||
EXPECT_NE(label_friend, dba1->Label("friend2"));
|
||||
EXPECT_EQ(dba1->LabelName(label_friend), "friend");
|
||||
GraphDbTypes::Label label_friend = dba.Label("friend");
|
||||
EXPECT_EQ(label_friend, dba.Label("friend"));
|
||||
EXPECT_NE(label_friend, dba.Label("friend2"));
|
||||
EXPECT_EQ(dba.LabelName(label_friend), "friend");
|
||||
|
||||
// test that getting labels through a different accessor works
|
||||
EXPECT_EQ(label_friend, dbms.active()->Label("friend"));
|
||||
EXPECT_NE(label_friend, dbms.active()->Label("friend2"));
|
||||
EXPECT_EQ(label_friend, GraphDbAccessor(db).Label("friend"));
|
||||
EXPECT_NE(label_friend, GraphDbAccessor(db).Label("friend2"));
|
||||
}
|
||||
|
||||
TEST(GraphDbAccessorTest, EdgeTypes) {
|
||||
Dbms dbms;
|
||||
auto dba1 = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
|
||||
GraphDbTypes::EdgeType edge_type = dba1->EdgeType("likes");
|
||||
EXPECT_EQ(edge_type, dba1->EdgeType("likes"));
|
||||
EXPECT_NE(edge_type, dba1->EdgeType("hates"));
|
||||
EXPECT_EQ(dba1->EdgeTypeName(edge_type), "likes");
|
||||
GraphDbTypes::EdgeType edge_type = dba.EdgeType("likes");
|
||||
EXPECT_EQ(edge_type, dba.EdgeType("likes"));
|
||||
EXPECT_NE(edge_type, dba.EdgeType("hates"));
|
||||
EXPECT_EQ(dba.EdgeTypeName(edge_type), "likes");
|
||||
|
||||
// test that getting labels through a different accessor works
|
||||
EXPECT_EQ(edge_type, dbms.active()->EdgeType("likes"));
|
||||
EXPECT_NE(edge_type, dbms.active()->EdgeType("hates"));
|
||||
EXPECT_EQ(edge_type, GraphDbAccessor(db).EdgeType("likes"));
|
||||
EXPECT_NE(edge_type, GraphDbAccessor(db).EdgeType("hates"));
|
||||
}
|
||||
|
||||
TEST(GraphDbAccessorTest, Properties) {
|
||||
Dbms dbms;
|
||||
auto dba1 = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
|
||||
GraphDbTypes::EdgeType prop = dba1->Property("name");
|
||||
EXPECT_EQ(prop, dba1->Property("name"));
|
||||
EXPECT_NE(prop, dba1->Property("surname"));
|
||||
EXPECT_EQ(dba1->PropertyName(prop), "name");
|
||||
GraphDbTypes::EdgeType prop = dba.Property("name");
|
||||
EXPECT_EQ(prop, dba.Property("name"));
|
||||
EXPECT_NE(prop, dba.Property("surname"));
|
||||
EXPECT_EQ(dba.PropertyName(prop), "name");
|
||||
|
||||
// test that getting labels through a different accessor works
|
||||
EXPECT_EQ(prop, dbms.active()->Property("name"));
|
||||
EXPECT_NE(prop, dbms.active()->Property("surname"));
|
||||
EXPECT_EQ(prop, GraphDbAccessor(db).Property("name"));
|
||||
EXPECT_NE(prop, GraphDbAccessor(db).Property("surname"));
|
||||
}
|
||||
|
||||
TEST(GraphDbAccessorTest, Transfer) {
|
||||
Dbms dbms;
|
||||
GraphDb db;
|
||||
|
||||
auto dba1 = dbms.active();
|
||||
auto prop = dba1->Property("property");
|
||||
VertexAccessor v1 = dba1->InsertVertex();
|
||||
GraphDbAccessor dba1(db);
|
||||
auto prop = dba1.Property("property");
|
||||
VertexAccessor v1 = dba1.InsertVertex();
|
||||
v1.PropsSet(prop, 1);
|
||||
VertexAccessor v2 = dba1->InsertVertex();
|
||||
VertexAccessor v2 = dba1.InsertVertex();
|
||||
v2.PropsSet(prop, 2);
|
||||
EdgeAccessor e12 = dba1->InsertEdge(v1, v2, dba1->EdgeType("et"));
|
||||
EdgeAccessor e12 = dba1.InsertEdge(v1, v2, dba1.EdgeType("et"));
|
||||
e12.PropsSet(prop, 12);
|
||||
|
||||
// make dba2 that has dba1 in it's snapshot, so data isn't visible
|
||||
auto dba2 = dbms.active();
|
||||
EXPECT_EQ(dba2->Transfer(v1), std::experimental::nullopt);
|
||||
EXPECT_EQ(dba2->Transfer(e12), std::experimental::nullopt);
|
||||
GraphDbAccessor dba2(db);
|
||||
EXPECT_EQ(dba2.Transfer(v1), std::experimental::nullopt);
|
||||
EXPECT_EQ(dba2.Transfer(e12), std::experimental::nullopt);
|
||||
|
||||
// make dba3 that does not have dba1 in it's snapshot
|
||||
dba1->Commit();
|
||||
auto dba3 = dbms.active();
|
||||
dba1.Commit();
|
||||
GraphDbAccessor dba3(db);
|
||||
// we can transfer accessors even though the GraphDbAccessor they
|
||||
// belong to is not alive anymore
|
||||
EXPECT_EQ(dba3->Transfer(v1)->PropsAt(prop).Value<int64_t>(), 1);
|
||||
EXPECT_EQ(dba3->Transfer(e12)->PropsAt(prop).Value<int64_t>(), 12);
|
||||
EXPECT_EQ(dba3.Transfer(v1)->PropsAt(prop).Value<int64_t>(), 1);
|
||||
EXPECT_EQ(dba3.Transfer(e12)->PropsAt(prop).Value<int64_t>(), 12);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
@ -5,7 +5,6 @@
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "database/dbms.hpp"
|
||||
#include "database/graph_db_accessor.hpp"
|
||||
#include "utils/bound.hpp"
|
||||
|
||||
@ -22,8 +21,8 @@ auto Count(TIterable iterable) {
|
||||
*/
|
||||
class GraphDbAccessorIndex : public testing::Test {
|
||||
protected:
|
||||
Dbms dbms;
|
||||
std::unique_ptr<GraphDbAccessor> dba = dbms.active();
|
||||
GraphDb db;
|
||||
std::experimental::optional<GraphDbAccessor> dba{db};
|
||||
GraphDbTypes::Property property = dba->Property("property");
|
||||
GraphDbTypes::Label label = dba->Label("label");
|
||||
GraphDbTypes::EdgeType edge_type = dba->EdgeType("edge_type");
|
||||
@ -44,8 +43,7 @@ class GraphDbAccessorIndex : public testing::Test {
|
||||
// commits the current dba, and replaces it with a new one
|
||||
void Commit() {
|
||||
dba->Commit();
|
||||
auto dba2 = dbms.active();
|
||||
dba.swap(dba2);
|
||||
dba.emplace(db);
|
||||
}
|
||||
};
|
||||
|
||||
@ -134,20 +132,19 @@ TEST_F(GraphDbAccessorIndex, LabelPropertyIndexCount) {
|
||||
}
|
||||
|
||||
TEST(GraphDbAccessorIndexApi, LabelPropertyBuildIndexConcurrent) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
|
||||
// We need to build indices in other threads.
|
||||
auto build_index_async = [&dbms](int &success, int index) {
|
||||
std::thread([&dbms, &success, index]() {
|
||||
auto dba = dbms.active();
|
||||
auto build_index_async = [&db](int &success, int index) {
|
||||
std::thread([&db, &success, index]() {
|
||||
GraphDbAccessor dba(db);
|
||||
try {
|
||||
dba->BuildIndex(dba->Label("l" + std::to_string(index)),
|
||||
dba->Property("p" + std::to_string(index)));
|
||||
dba->Commit();
|
||||
dba.BuildIndex(dba.Label("l" + std::to_string(index)),
|
||||
dba.Property("p" + std::to_string(index)));
|
||||
success = 1;
|
||||
} catch (IndexBuildInProgressException &) {
|
||||
dba->Abort();
|
||||
dba.Abort();
|
||||
success = 0;
|
||||
}
|
||||
}).detach();
|
||||
@ -166,7 +163,7 @@ TEST(GraphDbAccessorIndexApi, LabelPropertyBuildIndexConcurrent) {
|
||||
EXPECT_EQ(build_2_success, 0);
|
||||
|
||||
// End dba and expect that first build index finished successfully.
|
||||
dba->Commit();
|
||||
dba.Commit();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(30));
|
||||
EXPECT_EQ(build_1_success, 1);
|
||||
}
|
||||
|
@ -1,12 +1,10 @@
|
||||
#include <cstdlib>
|
||||
|
||||
#include "communication/result_stream_faker.hpp"
|
||||
#include "database/dbms.hpp"
|
||||
#include "database/graph_db_accessor.hpp"
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "query/exceptions.hpp"
|
||||
#include "query/exceptions.hpp"
|
||||
#include "query/interpreter.hpp"
|
||||
#include "query/typed_value.hpp"
|
||||
#include "query_common.hpp"
|
||||
@ -20,11 +18,11 @@ namespace {
|
||||
// ast is read from cache.
|
||||
TEST(Interpreter, AstCache) {
|
||||
query::Interpreter interpreter;
|
||||
Dbms dbms;
|
||||
GraphDb db;
|
||||
{
|
||||
ResultStreamFaker stream;
|
||||
auto dba = dbms.active();
|
||||
interpreter.Interpret("RETURN 2 + 3", *dba, stream, {}, false);
|
||||
GraphDbAccessor dba(db);
|
||||
interpreter.Interpret("RETURN 2 + 3", dba, stream, {}, false);
|
||||
ASSERT_EQ(stream.GetHeader().size(), 1U);
|
||||
EXPECT_EQ(stream.GetHeader()[0], "2 + 3");
|
||||
ASSERT_EQ(stream.GetResults().size(), 1U);
|
||||
@ -34,8 +32,8 @@ TEST(Interpreter, AstCache) {
|
||||
{
|
||||
// Cached ast, different literals.
|
||||
ResultStreamFaker stream;
|
||||
auto dba = dbms.active();
|
||||
interpreter.Interpret("RETURN 5 + 4", *dba, stream, {}, false);
|
||||
GraphDbAccessor dba(db);
|
||||
interpreter.Interpret("RETURN 5 + 4", dba, stream, {}, false);
|
||||
ASSERT_EQ(stream.GetResults().size(), 1U);
|
||||
ASSERT_EQ(stream.GetResults()[0].size(), 1U);
|
||||
ASSERT_EQ(stream.GetResults()[0][0].Value<int64_t>(), 9);
|
||||
@ -43,8 +41,8 @@ TEST(Interpreter, AstCache) {
|
||||
{
|
||||
// Different ast (because of different types).
|
||||
ResultStreamFaker stream;
|
||||
auto dba = dbms.active();
|
||||
interpreter.Interpret("RETURN 5.5 + 4", *dba, stream, {}, false);
|
||||
GraphDbAccessor dba(db);
|
||||
interpreter.Interpret("RETURN 5.5 + 4", dba, stream, {}, false);
|
||||
ASSERT_EQ(stream.GetResults().size(), 1U);
|
||||
ASSERT_EQ(stream.GetResults()[0].size(), 1U);
|
||||
ASSERT_EQ(stream.GetResults()[0][0].Value<double>(), 9.5);
|
||||
@ -52,8 +50,8 @@ TEST(Interpreter, AstCache) {
|
||||
{
|
||||
// Cached ast, same literals.
|
||||
ResultStreamFaker stream;
|
||||
auto dba = dbms.active();
|
||||
interpreter.Interpret("RETURN 2 + 3", *dba, stream, {}, false);
|
||||
GraphDbAccessor dba(db);
|
||||
interpreter.Interpret("RETURN 2 + 3", dba, stream, {}, false);
|
||||
ASSERT_EQ(stream.GetResults().size(), 1U);
|
||||
ASSERT_EQ(stream.GetResults()[0].size(), 1U);
|
||||
ASSERT_EQ(stream.GetResults()[0][0].Value<int64_t>(), 5);
|
||||
@ -61,8 +59,8 @@ TEST(Interpreter, AstCache) {
|
||||
{
|
||||
// Cached ast, different literals.
|
||||
ResultStreamFaker stream;
|
||||
auto dba = dbms.active();
|
||||
interpreter.Interpret("RETURN 10.5 + 1", *dba, stream, {}, false);
|
||||
GraphDbAccessor dba(db);
|
||||
interpreter.Interpret("RETURN 10.5 + 1", dba, stream, {}, false);
|
||||
ASSERT_EQ(stream.GetResults().size(), 1U);
|
||||
ASSERT_EQ(stream.GetResults()[0].size(), 1U);
|
||||
ASSERT_EQ(stream.GetResults()[0][0].Value<double>(), 11.5);
|
||||
@ -70,8 +68,8 @@ TEST(Interpreter, AstCache) {
|
||||
{
|
||||
// Cached ast, same literals, different whitespaces.
|
||||
ResultStreamFaker stream;
|
||||
auto dba = dbms.active();
|
||||
interpreter.Interpret("RETURN 10.5 + 1", *dba, stream, {}, false);
|
||||
GraphDbAccessor dba(db);
|
||||
interpreter.Interpret("RETURN 10.5 + 1", dba, stream, {}, false);
|
||||
ASSERT_EQ(stream.GetResults().size(), 1U);
|
||||
ASSERT_EQ(stream.GetResults()[0].size(), 1U);
|
||||
ASSERT_EQ(stream.GetResults()[0][0].Value<double>(), 11.5);
|
||||
@ -79,8 +77,8 @@ TEST(Interpreter, AstCache) {
|
||||
{
|
||||
// Cached ast, same literals, different named header.
|
||||
ResultStreamFaker stream;
|
||||
auto dba = dbms.active();
|
||||
interpreter.Interpret("RETURN 10.5+1", *dba, stream, {}, false);
|
||||
GraphDbAccessor dba(db);
|
||||
interpreter.Interpret("RETURN 10.5+1", dba, stream, {}, false);
|
||||
ASSERT_EQ(stream.GetHeader().size(), 1U);
|
||||
EXPECT_EQ(stream.GetHeader()[0], "10.5+1");
|
||||
ASSERT_EQ(stream.GetResults().size(), 1U);
|
||||
@ -92,11 +90,11 @@ TEST(Interpreter, AstCache) {
|
||||
// Run query with same ast multiple times with different parameters.
|
||||
TEST(Interpreter, Parameters) {
|
||||
query::Interpreter interpreter;
|
||||
Dbms dbms;
|
||||
GraphDb db;
|
||||
{
|
||||
ResultStreamFaker stream;
|
||||
auto dba = dbms.active();
|
||||
interpreter.Interpret("RETURN $2 + $`a b`", *dba, stream,
|
||||
GraphDbAccessor dba(db);
|
||||
interpreter.Interpret("RETURN $2 + $`a b`", dba, stream,
|
||||
{{"2", 10}, {"a b", 15}}, false);
|
||||
ASSERT_EQ(stream.GetHeader().size(), 1U);
|
||||
EXPECT_EQ(stream.GetHeader()[0], "$2 + $`a b`");
|
||||
@ -107,8 +105,8 @@ TEST(Interpreter, Parameters) {
|
||||
{
|
||||
// Not needed parameter.
|
||||
ResultStreamFaker stream;
|
||||
auto dba = dbms.active();
|
||||
interpreter.Interpret("RETURN $2 + $`a b`", *dba, stream,
|
||||
GraphDbAccessor dba(db);
|
||||
interpreter.Interpret("RETURN $2 + $`a b`", dba, stream,
|
||||
{{"2", 10}, {"a b", 15}, {"c", 10}}, false);
|
||||
ASSERT_EQ(stream.GetHeader().size(), 1U);
|
||||
EXPECT_EQ(stream.GetHeader()[0], "$2 + $`a b`");
|
||||
@ -119,8 +117,8 @@ TEST(Interpreter, Parameters) {
|
||||
{
|
||||
// Cached ast, different parameters.
|
||||
ResultStreamFaker stream;
|
||||
auto dba = dbms.active();
|
||||
interpreter.Interpret("RETURN $2 + $`a b`", *dba, stream,
|
||||
GraphDbAccessor dba(db);
|
||||
interpreter.Interpret("RETURN $2 + $`a b`", dba, stream,
|
||||
{{"2", "da"}, {"a b", "ne"}}, false);
|
||||
ASSERT_EQ(stream.GetResults().size(), 1U);
|
||||
ASSERT_EQ(stream.GetResults()[0].size(), 1U);
|
||||
@ -129,8 +127,8 @@ TEST(Interpreter, Parameters) {
|
||||
{
|
||||
// Non-primitive literal.
|
||||
ResultStreamFaker stream;
|
||||
auto dba = dbms.active();
|
||||
interpreter.Interpret("RETURN $2", *dba, stream,
|
||||
GraphDbAccessor dba(db);
|
||||
interpreter.Interpret("RETURN $2", dba, stream,
|
||||
{{"2", std::vector<query::TypedValue>{5, 2, 3}}},
|
||||
false);
|
||||
ASSERT_EQ(stream.GetResults().size(), 1U);
|
||||
@ -142,8 +140,8 @@ TEST(Interpreter, Parameters) {
|
||||
{
|
||||
// Cached ast, unprovided parameter.
|
||||
ResultStreamFaker stream;
|
||||
auto dba = dbms.active();
|
||||
ASSERT_THROW(interpreter.Interpret("RETURN $2 + $`a b`", *dba, stream,
|
||||
GraphDbAccessor dba(db);
|
||||
ASSERT_THROW(interpreter.Interpret("RETURN $2 + $`a b`", dba, stream,
|
||||
{{"2", "da"}, {"ab", "ne"}}, false),
|
||||
query::UnprovidedParameterError);
|
||||
}
|
||||
@ -161,26 +159,26 @@ TEST(Interpreter, Bfs) {
|
||||
const auto kId = "id";
|
||||
|
||||
query::Interpreter interpreter;
|
||||
Dbms dbms;
|
||||
GraphDb db;
|
||||
ResultStreamFaker stream;
|
||||
std::vector<std::vector<VertexAccessor>> levels(kNumLevels);
|
||||
int id = 0;
|
||||
|
||||
// Set up.
|
||||
{
|
||||
auto dba = dbms.active();
|
||||
GraphDbAccessor dba(db);
|
||||
auto add_node = [&](int level, bool reachable) {
|
||||
auto node = dba->InsertVertex();
|
||||
node.PropsSet(dba->Property(kId), id++);
|
||||
node.PropsSet(dba->Property(kReachable), reachable);
|
||||
auto node = dba.InsertVertex();
|
||||
node.PropsSet(dba.Property(kId), id++);
|
||||
node.PropsSet(dba.Property(kReachable), reachable);
|
||||
levels[level].push_back(node);
|
||||
return node;
|
||||
};
|
||||
|
||||
auto add_edge = [&](VertexAccessor &v1, VertexAccessor &v2,
|
||||
bool reachable) {
|
||||
auto edge = dba->InsertEdge(v1, v2, dba->EdgeType("edge"));
|
||||
edge.PropsSet(dba->Property(kReachable), reachable);
|
||||
auto edge = dba.InsertEdge(v1, v2, dba.EdgeType("edge"));
|
||||
edge.PropsSet(dba.Property(kReachable), reachable);
|
||||
};
|
||||
|
||||
// Add source node.
|
||||
@ -218,15 +216,15 @@ TEST(Interpreter, Bfs) {
|
||||
add_edge(node1, node2, false);
|
||||
}
|
||||
|
||||
dba->Commit();
|
||||
dba.Commit();
|
||||
}
|
||||
|
||||
auto dba = dbms.active();
|
||||
GraphDbAccessor dba(db);
|
||||
|
||||
interpreter.Interpret(
|
||||
"MATCH (n {id: 0})-[r *bfs..5 (e, n | n.reachable and e.reachable)]->(m) "
|
||||
"RETURN r",
|
||||
*dba, stream, {}, false);
|
||||
dba, stream, {}, false);
|
||||
|
||||
ASSERT_EQ(stream.GetHeader().size(), 1U);
|
||||
EXPECT_EQ(stream.GetHeader()[0], "r");
|
||||
@ -243,13 +241,13 @@ TEST(Interpreter, Bfs) {
|
||||
// shorter to longer ones.
|
||||
EXPECT_EQ(edges.size(), expected_level);
|
||||
// Check that starting node is correct.
|
||||
EXPECT_EQ(edges[0].from().PropsAt(dba->Property(kId)).Value<int64_t>(), 0);
|
||||
EXPECT_EQ(edges[0].from().PropsAt(dba.Property(kId)).Value<int64_t>(), 0);
|
||||
for (int i = 1; i < static_cast<int>(edges.size()); ++i) {
|
||||
// Check that edges form a connected path.
|
||||
EXPECT_EQ(edges[i - 1].to(), edges[i].from());
|
||||
}
|
||||
auto matched_id =
|
||||
edges.back().to().PropsAt(dba->Property(kId)).Value<int64_t>();
|
||||
edges.back().to().PropsAt(dba.Property(kId)).Value<int64_t>();
|
||||
// Check that we didn't match that node already.
|
||||
EXPECT_TRUE(matched_ids.insert(matched_id).second);
|
||||
// Check that shortest path was found.
|
||||
@ -264,16 +262,16 @@ TEST(Interpreter, Bfs) {
|
||||
|
||||
TEST(Interpreter, CreateIndexInMulticommandTransaction) {
|
||||
query::Interpreter interpreter;
|
||||
Dbms dbms;
|
||||
GraphDb db;
|
||||
{
|
||||
ResultStreamFaker stream;
|
||||
auto dba = dbms.active();
|
||||
GraphDbAccessor dba(db);
|
||||
ASSERT_THROW(
|
||||
interpreter.Interpret("CREATE INDEX ON :X(y)", *dba, stream, {}, true),
|
||||
interpreter.Interpret("CREATE INDEX ON :X(y)", dba, stream, {}, true),
|
||||
query::IndexInMulticommandTxException);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
|
@ -5,9 +5,8 @@
|
||||
/// example:
|
||||
///
|
||||
/// AstTreeStorage storage; // Macros rely on storage being in scope.
|
||||
/// // PROPERTY_LOOKUP and PROPERTY_PAIR macros also rely on a graph DB
|
||||
/// // accessor
|
||||
/// std::unique_ptr<GraphDbAccessor> dba;
|
||||
/// // PROPERTY_LOOKUP and PROPERTY_PAIR macros also rely on GraphDb
|
||||
/// GraphDb db;
|
||||
///
|
||||
/// QUERY(MATCH(PATTERN(NODE("n"), EDGE("e"), NODE("m"))),
|
||||
/// WHERE(LESS(PROPERTY_LOOKUP("e", edge_prop), LITERAL(3))),
|
||||
@ -30,7 +29,6 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "database/dbms.hpp"
|
||||
#include "database/graph_db_datatypes.hpp"
|
||||
#include "query/frontend/ast/ast.hpp"
|
||||
#include "query/interpret/awesome_memgraph_functions.hpp"
|
||||
@ -110,29 +108,27 @@ auto GetOrderBy(T... exprs) {
|
||||
///
|
||||
/// Name is used to create the Identifier which is used for property lookup.
|
||||
///
|
||||
auto GetPropertyLookup(AstTreeStorage &storage,
|
||||
std::unique_ptr<GraphDbAccessor> &dba,
|
||||
auto GetPropertyLookup(AstTreeStorage &storage, GraphDb &db,
|
||||
const std::string &name,
|
||||
GraphDbTypes::Property property) {
|
||||
GraphDbAccessor dba(db);
|
||||
return storage.Create<PropertyLookup>(storage.Create<Identifier>(name),
|
||||
dba->PropertyName(property), property);
|
||||
dba.PropertyName(property), property);
|
||||
}
|
||||
auto GetPropertyLookup(AstTreeStorage &storage,
|
||||
std::unique_ptr<GraphDbAccessor> &dba, Expression *expr,
|
||||
auto GetPropertyLookup(AstTreeStorage &storage, GraphDb &db, Expression *expr,
|
||||
GraphDbTypes::Property property) {
|
||||
return storage.Create<PropertyLookup>(expr, dba->PropertyName(property),
|
||||
GraphDbAccessor dba(db);
|
||||
return storage.Create<PropertyLookup>(expr, dba.PropertyName(property),
|
||||
property);
|
||||
}
|
||||
auto GetPropertyLookup(
|
||||
AstTreeStorage &storage, std::unique_ptr<GraphDbAccessor> &,
|
||||
const std::string &name,
|
||||
AstTreeStorage &storage, GraphDb &, const std::string &name,
|
||||
const std::pair<std::string, GraphDbTypes::Property> &prop_pair) {
|
||||
return storage.Create<PropertyLookup>(storage.Create<Identifier>(name),
|
||||
prop_pair.first, prop_pair.second);
|
||||
}
|
||||
auto GetPropertyLookup(
|
||||
AstTreeStorage &storage, std::unique_ptr<GraphDbAccessor> &,
|
||||
Expression *expr,
|
||||
AstTreeStorage &storage, GraphDb &, Expression *expr,
|
||||
const std::pair<std::string, GraphDbTypes::Property> &prop_pair) {
|
||||
return storage.Create<PropertyLookup>(expr, prop_pair.first,
|
||||
prop_pair.second);
|
||||
@ -497,9 +493,9 @@ auto GetMerge(AstTreeStorage &storage, Pattern *pattern, OnMatch on_match,
|
||||
std::unordered_map<std::pair<std::string, GraphDbTypes::Property>, \
|
||||
query::Expression *>{__VA_ARGS__})
|
||||
#define PROPERTY_PAIR(property_name) \
|
||||
std::make_pair(property_name, dba->Property(property_name))
|
||||
std::make_pair(property_name, GraphDbAccessor(db).Property(property_name))
|
||||
#define PROPERTY_LOOKUP(...) \
|
||||
query::test_common::GetPropertyLookup(storage, dba, __VA_ARGS__)
|
||||
query::test_common::GetPropertyLookup(storage, db, __VA_ARGS__)
|
||||
#define NEXPR(name, expr) storage.Create<query::NamedExpression>((name), (expr))
|
||||
// AS is alternative to NEXPR which does not initialize NamedExpression with
|
||||
// Expression. It should be used with RETURN or WITH. For example:
|
||||
|
@ -1,7 +1,6 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <memory>
|
||||
|
||||
#include "database/dbms.hpp"
|
||||
#include "query/frontend/ast/ast.hpp"
|
||||
#include "query/frontend/semantic/symbol_table.hpp"
|
||||
#include "query/plan/cost_estimator.hpp"
|
||||
@ -22,8 +21,8 @@ using MiscParam = CostEstimator<GraphDbAccessor>::MiscParam;
|
||||
* estimation testing. */
|
||||
class QueryCostEstimator : public ::testing::Test {
|
||||
protected:
|
||||
Dbms dbms;
|
||||
std::unique_ptr<GraphDbAccessor> dba = dbms.active();
|
||||
GraphDb db;
|
||||
std::experimental::optional<GraphDbAccessor> dba{db};
|
||||
GraphDbTypes::Label label = dba->Label("label");
|
||||
GraphDbTypes::Property property = dba->Property("property");
|
||||
|
||||
@ -39,8 +38,7 @@ class QueryCostEstimator : public ::testing::Test {
|
||||
void SetUp() {
|
||||
// create the index in the current db accessor and then swap it to a new one
|
||||
dba->BuildIndex(label, property);
|
||||
auto new_dba = dbms.active();
|
||||
dba.swap(new_dba);
|
||||
dba.emplace(db);
|
||||
}
|
||||
|
||||
Symbol NextSymbol() {
|
||||
@ -200,11 +198,12 @@ TEST_F(QueryCostEstimator, ExpandUniquenessFilter) {
|
||||
}
|
||||
|
||||
TEST_F(QueryCostEstimator, UnwindLiteral) {
|
||||
TEST_OP(MakeOp<query::plan::Unwind>(
|
||||
last_op_, storage_.Create<ListLiteral>(
|
||||
std::vector<Expression *>(7, nullptr)),
|
||||
NextSymbol()),
|
||||
CostParam::kUnwind, 7);
|
||||
TEST_OP(
|
||||
MakeOp<query::plan::Unwind>(
|
||||
last_op_,
|
||||
storage_.Create<ListLiteral>(std::vector<Expression *>(7, nullptr)),
|
||||
NextSymbol()),
|
||||
CostParam::kUnwind, 7);
|
||||
}
|
||||
|
||||
TEST_F(QueryCostEstimator, UnwindNoLiteral) {
|
||||
|
@ -7,7 +7,6 @@
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "database/dbms.hpp"
|
||||
#include "database/graph_db_accessor.hpp"
|
||||
#include "database/graph_db_datatypes.hpp"
|
||||
#include "query/frontend/ast/ast.hpp"
|
||||
@ -20,9 +19,9 @@
|
||||
#include "query_common.hpp"
|
||||
|
||||
using namespace query;
|
||||
using testing::UnorderedElementsAre;
|
||||
using testing::ElementsAre;
|
||||
using query::test_common::ToList;
|
||||
using testing::ElementsAre;
|
||||
using testing::UnorderedElementsAre;
|
||||
|
||||
namespace {
|
||||
|
||||
@ -30,20 +29,20 @@ struct NoContextExpressionEvaluator {
|
||||
NoContextExpressionEvaluator() {}
|
||||
Frame frame{128};
|
||||
SymbolTable symbol_table;
|
||||
Dbms dbms;
|
||||
std::unique_ptr<GraphDbAccessor> dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba{db};
|
||||
Parameters parameters;
|
||||
ExpressionEvaluator eval{frame, parameters, symbol_table, *dba};
|
||||
ExpressionEvaluator eval{frame, parameters, symbol_table, dba};
|
||||
};
|
||||
|
||||
TypedValue EvaluateFunction(const std::string &function_name,
|
||||
const std::vector<TypedValue> &args, Dbms &dbms) {
|
||||
const std::vector<TypedValue> &args, GraphDb &db) {
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
auto dba = dbms.active();
|
||||
GraphDbAccessor dba(db);
|
||||
Frame frame{128};
|
||||
Parameters parameters;
|
||||
ExpressionEvaluator eval{frame, parameters, symbol_table, *dba};
|
||||
ExpressionEvaluator eval{frame, parameters, symbol_table, dba};
|
||||
|
||||
std::vector<Expression *> expressions;
|
||||
for (const auto &arg : args) {
|
||||
@ -56,8 +55,8 @@ TypedValue EvaluateFunction(const std::string &function_name,
|
||||
|
||||
TypedValue EvaluateFunction(const std::string &function_name,
|
||||
const std::vector<TypedValue> &args) {
|
||||
Dbms dbms;
|
||||
return EvaluateFunction(function_name, args, dbms);
|
||||
GraphDb db;
|
||||
return EvaluateFunction(function_name, args, db);
|
||||
}
|
||||
|
||||
TEST(ExpressionEvaluator, OrOperator) {
|
||||
@ -372,8 +371,8 @@ TEST(ExpressionEvaluator, ListMapIndexingOperator) {
|
||||
TEST(ExpressionEvaluator, MapIndexing) {
|
||||
AstTreeStorage storage;
|
||||
NoContextExpressionEvaluator eval;
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto *map_literal = storage.Create<MapLiteral>(
|
||||
std::unordered_map<std::pair<std::string, GraphDbTypes::Property>,
|
||||
Expression *>{
|
||||
@ -579,8 +578,8 @@ class ExpressionEvaluatorPropertyLookup : public testing::Test {
|
||||
protected:
|
||||
AstTreeStorage storage;
|
||||
NoContextExpressionEvaluator eval;
|
||||
Dbms dbms;
|
||||
std::unique_ptr<GraphDbAccessor> dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba{db};
|
||||
std::pair<std::string, GraphDbTypes::Property> prop_age =
|
||||
PROPERTY_PAIR("age");
|
||||
std::pair<std::string, GraphDbTypes::Property> prop_height =
|
||||
@ -597,7 +596,7 @@ class ExpressionEvaluatorPropertyLookup : public testing::Test {
|
||||
};
|
||||
|
||||
TEST_F(ExpressionEvaluatorPropertyLookup, Vertex) {
|
||||
auto v1 = dba->InsertVertex();
|
||||
auto v1 = dba.InsertVertex();
|
||||
v1.PropsSet(prop_age.second, 10);
|
||||
eval.frame[symbol] = v1;
|
||||
EXPECT_EQ(Value(prop_age).Value<int64_t>(), 10);
|
||||
@ -605,9 +604,9 @@ TEST_F(ExpressionEvaluatorPropertyLookup, Vertex) {
|
||||
}
|
||||
|
||||
TEST_F(ExpressionEvaluatorPropertyLookup, Edge) {
|
||||
auto v1 = dba->InsertVertex();
|
||||
auto v2 = dba->InsertVertex();
|
||||
auto e12 = dba->InsertEdge(v1, v2, dba->EdgeType("edge_type"));
|
||||
auto v1 = dba.InsertVertex();
|
||||
auto v2 = dba.InsertVertex();
|
||||
auto e12 = dba.InsertEdge(v1, v2, dba.EdgeType("edge_type"));
|
||||
e12.PropsSet(prop_age.second, 10);
|
||||
eval.frame[symbol] = e12;
|
||||
EXPECT_EQ(Value(prop_age).Value<int64_t>(), 10);
|
||||
@ -628,28 +627,28 @@ TEST_F(ExpressionEvaluatorPropertyLookup, MapLiteral) {
|
||||
TEST(ExpressionEvaluator, LabelsTest) {
|
||||
AstTreeStorage storage;
|
||||
NoContextExpressionEvaluator eval;
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto v1 = dba->InsertVertex();
|
||||
v1.add_label(dba->Label("ANIMAL"));
|
||||
v1.add_label(dba->Label("DOG"));
|
||||
v1.add_label(dba->Label("NICE_DOG"));
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto v1 = dba.InsertVertex();
|
||||
v1.add_label(dba.Label("ANIMAL"));
|
||||
v1.add_label(dba.Label("DOG"));
|
||||
v1.add_label(dba.Label("NICE_DOG"));
|
||||
auto *identifier = storage.Create<Identifier>("n");
|
||||
auto node_symbol = eval.symbol_table.CreateSymbol("n", true);
|
||||
eval.symbol_table[*identifier] = node_symbol;
|
||||
eval.frame[node_symbol] = v1;
|
||||
{
|
||||
auto *op = storage.Create<LabelsTest>(
|
||||
identifier, std::vector<GraphDbTypes::Label>{dba->Label("DOG"),
|
||||
dba->Label("ANIMAL")});
|
||||
identifier, std::vector<GraphDbTypes::Label>{dba.Label("DOG"),
|
||||
dba.Label("ANIMAL")});
|
||||
auto value = op->Accept(eval.eval);
|
||||
EXPECT_EQ(value.Value<bool>(), true);
|
||||
}
|
||||
{
|
||||
auto *op = storage.Create<LabelsTest>(
|
||||
identifier,
|
||||
std::vector<GraphDbTypes::Label>{
|
||||
dba->Label("DOG"), dba->Label("BAD_DOG"), dba->Label("ANIMAL")});
|
||||
std::vector<GraphDbTypes::Label>{dba.Label("DOG"), dba.Label("BAD_DOG"),
|
||||
dba.Label("ANIMAL")});
|
||||
auto value = op->Accept(eval.eval);
|
||||
EXPECT_EQ(value.Value<bool>(), false);
|
||||
}
|
||||
@ -657,8 +656,8 @@ TEST(ExpressionEvaluator, LabelsTest) {
|
||||
eval.frame[node_symbol] = TypedValue::Null;
|
||||
auto *op = storage.Create<LabelsTest>(
|
||||
identifier,
|
||||
std::vector<GraphDbTypes::Label>{
|
||||
dba->Label("DOG"), dba->Label("BAD_DOG"), dba->Label("ANIMAL")});
|
||||
std::vector<GraphDbTypes::Label>{dba.Label("DOG"), dba.Label("BAD_DOG"),
|
||||
dba.Label("ANIMAL")});
|
||||
auto value = op->Accept(eval.eval);
|
||||
EXPECT_TRUE(value.IsNull());
|
||||
}
|
||||
@ -673,10 +672,10 @@ TEST(ExpressionEvaluator, Aggregation) {
|
||||
symbol_table[*aggr] = aggr_sym;
|
||||
Frame frame{symbol_table.max_position()};
|
||||
frame[aggr_sym] = TypedValue(1);
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
Parameters parameters;
|
||||
ExpressionEvaluator eval{frame, parameters, symbol_table, *dba};
|
||||
ExpressionEvaluator eval{frame, parameters, symbol_table, dba};
|
||||
auto value = aggr->Accept(eval);
|
||||
EXPECT_EQ(value.Value<int64_t>(), 1);
|
||||
}
|
||||
@ -711,16 +710,16 @@ TEST(ExpressionEvaluator, FunctionEndNode) {
|
||||
ASSERT_THROW(EvaluateFunction("ENDNODE", {}), QueryRuntimeException);
|
||||
ASSERT_EQ(EvaluateFunction("ENDNODE", {TypedValue::Null}).type(),
|
||||
TypedValue::Type::Null);
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto v1 = dba->InsertVertex();
|
||||
v1.add_label(dba->Label("label1"));
|
||||
auto v2 = dba->InsertVertex();
|
||||
v2.add_label(dba->Label("label2"));
|
||||
auto e = dba->InsertEdge(v1, v2, dba->EdgeType("t"));
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto v1 = dba.InsertVertex();
|
||||
v1.add_label(dba.Label("label1"));
|
||||
auto v2 = dba.InsertVertex();
|
||||
v2.add_label(dba.Label("label2"));
|
||||
auto e = dba.InsertEdge(v1, v2, dba.EdgeType("t"));
|
||||
ASSERT_TRUE(EvaluateFunction("ENDNODE", {e})
|
||||
.Value<VertexAccessor>()
|
||||
.has_label(dba->Label("label2")));
|
||||
.has_label(dba.Label("label2")));
|
||||
ASSERT_THROW(EvaluateFunction("ENDNODE", {2}), QueryRuntimeException);
|
||||
}
|
||||
|
||||
@ -740,15 +739,15 @@ TEST(ExpressionEvaluator, FunctionProperties) {
|
||||
ASSERT_THROW(EvaluateFunction("PROPERTIES", {}), QueryRuntimeException);
|
||||
ASSERT_EQ(EvaluateFunction("PROPERTIES", {TypedValue::Null}).type(),
|
||||
TypedValue::Type::Null);
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto v1 = dba->InsertVertex();
|
||||
v1.PropsSet(dba->Property("height"), 5);
|
||||
v1.PropsSet(dba->Property("age"), 10);
|
||||
auto v2 = dba->InsertVertex();
|
||||
auto e = dba->InsertEdge(v1, v2, dba->EdgeType("type1"));
|
||||
e.PropsSet(dba->Property("height"), 3);
|
||||
e.PropsSet(dba->Property("age"), 15);
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto v1 = dba.InsertVertex();
|
||||
v1.PropsSet(dba.Property("height"), 5);
|
||||
v1.PropsSet(dba.Property("age"), 10);
|
||||
auto v2 = dba.InsertVertex();
|
||||
auto e = dba.InsertEdge(v1, v2, dba.EdgeType("type1"));
|
||||
e.PropsSet(dba.Property("height"), 3);
|
||||
e.PropsSet(dba.Property("age"), 15);
|
||||
|
||||
auto prop_values_to_int = [](TypedValue t) {
|
||||
std::unordered_map<std::string, int> properties;
|
||||
@ -792,13 +791,13 @@ TEST(ExpressionEvaluator, FunctionSize) {
|
||||
3);
|
||||
ASSERT_THROW(EvaluateFunction("SIZE", {5}), QueryRuntimeException);
|
||||
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto v0 = dba->InsertVertex();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto v0 = dba.InsertVertex();
|
||||
query::Path path(v0);
|
||||
EXPECT_EQ(EvaluateFunction("SIZE", {path}).ValueInt(), 0);
|
||||
auto v1 = dba->InsertVertex();
|
||||
path.Expand(dba->InsertEdge(v0, v1, dba->EdgeType("type")));
|
||||
auto v1 = dba.InsertVertex();
|
||||
path.Expand(dba.InsertEdge(v0, v1, dba.EdgeType("type")));
|
||||
path.Expand(v1);
|
||||
EXPECT_EQ(EvaluateFunction("SIZE", {path}).ValueInt(), 1);
|
||||
}
|
||||
@ -807,16 +806,16 @@ TEST(ExpressionEvaluator, FunctionStartNode) {
|
||||
ASSERT_THROW(EvaluateFunction("STARTNODE", {}), QueryRuntimeException);
|
||||
ASSERT_EQ(EvaluateFunction("STARTNODE", {TypedValue::Null}).type(),
|
||||
TypedValue::Type::Null);
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto v1 = dba->InsertVertex();
|
||||
v1.add_label(dba->Label("label1"));
|
||||
auto v2 = dba->InsertVertex();
|
||||
v2.add_label(dba->Label("label2"));
|
||||
auto e = dba->InsertEdge(v1, v2, dba->EdgeType("t"));
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto v1 = dba.InsertVertex();
|
||||
v1.add_label(dba.Label("label1"));
|
||||
auto v2 = dba.InsertVertex();
|
||||
v2.add_label(dba.Label("label2"));
|
||||
auto e = dba.InsertEdge(v1, v2, dba.EdgeType("t"));
|
||||
ASSERT_TRUE(EvaluateFunction("STARTNODE", {e})
|
||||
.Value<VertexAccessor>()
|
||||
.has_label(dba->Label("label1")));
|
||||
.has_label(dba.Label("label1")));
|
||||
ASSERT_THROW(EvaluateFunction("STARTNODE", {2}), QueryRuntimeException);
|
||||
}
|
||||
|
||||
@ -824,13 +823,13 @@ TEST(ExpressionEvaluator, FunctionDegree) {
|
||||
ASSERT_THROW(EvaluateFunction("DEGREE", {}), QueryRuntimeException);
|
||||
ASSERT_EQ(EvaluateFunction("DEGREE", {TypedValue::Null}).type(),
|
||||
TypedValue::Type::Null);
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto v1 = dba->InsertVertex();
|
||||
auto v2 = dba->InsertVertex();
|
||||
auto v3 = dba->InsertVertex();
|
||||
auto e12 = dba->InsertEdge(v1, v2, dba->EdgeType("t"));
|
||||
dba->InsertEdge(v3, v2, dba->EdgeType("t"));
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto v1 = dba.InsertVertex();
|
||||
auto v2 = dba.InsertVertex();
|
||||
auto v3 = dba.InsertVertex();
|
||||
auto e12 = dba.InsertEdge(v1, v2, dba.EdgeType("t"));
|
||||
dba.InsertEdge(v3, v2, dba.EdgeType("t"));
|
||||
ASSERT_EQ(EvaluateFunction("DEGREE", {v1}).Value<int64_t>(), 1);
|
||||
ASSERT_EQ(EvaluateFunction("DEGREE", {v2}).Value<int64_t>(), 2);
|
||||
ASSERT_EQ(EvaluateFunction("DEGREE", {v3}).Value<int64_t>(), 1);
|
||||
@ -881,13 +880,13 @@ TEST(ExpressionEvaluator, FunctionType) {
|
||||
ASSERT_THROW(EvaluateFunction("TYPE", {}), QueryRuntimeException);
|
||||
ASSERT_EQ(EvaluateFunction("TYPE", {TypedValue::Null}).type(),
|
||||
TypedValue::Type::Null);
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto v1 = dba->InsertVertex();
|
||||
v1.add_label(dba->Label("label1"));
|
||||
auto v2 = dba->InsertVertex();
|
||||
v2.add_label(dba->Label("label2"));
|
||||
auto e = dba->InsertEdge(v1, v2, dba->EdgeType("type1"));
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto v1 = dba.InsertVertex();
|
||||
v1.add_label(dba.Label("label1"));
|
||||
auto v2 = dba.InsertVertex();
|
||||
v2.add_label(dba.Label("label2"));
|
||||
auto e = dba.InsertEdge(v1, v2, dba.EdgeType("type1"));
|
||||
ASSERT_EQ(EvaluateFunction("TYPE", {e}).Value<std::string>(), "type1");
|
||||
ASSERT_THROW(EvaluateFunction("TYPE", {2}), QueryRuntimeException);
|
||||
}
|
||||
@ -896,11 +895,11 @@ TEST(ExpressionEvaluator, FunctionLabels) {
|
||||
ASSERT_THROW(EvaluateFunction("LABELS", {}), QueryRuntimeException);
|
||||
ASSERT_EQ(EvaluateFunction("LABELS", {TypedValue::Null}).type(),
|
||||
TypedValue::Type::Null);
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto v = dba->InsertVertex();
|
||||
v.add_label(dba->Label("label1"));
|
||||
v.add_label(dba->Label("label2"));
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto v = dba.InsertVertex();
|
||||
v.add_label(dba.Label("label1"));
|
||||
v.add_label(dba.Label("label2"));
|
||||
std::vector<std::string> labels;
|
||||
auto _labels =
|
||||
EvaluateFunction("LABELS", {v}).Value<std::vector<TypedValue>>();
|
||||
@ -941,15 +940,15 @@ TEST(ExpressionEvaluator, FunctionKeys) {
|
||||
ASSERT_THROW(EvaluateFunction("KEYS", {}), QueryRuntimeException);
|
||||
ASSERT_EQ(EvaluateFunction("KEYS", {TypedValue::Null}).type(),
|
||||
TypedValue::Type::Null);
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto v1 = dba->InsertVertex();
|
||||
v1.PropsSet(dba->Property("height"), 5);
|
||||
v1.PropsSet(dba->Property("age"), 10);
|
||||
auto v2 = dba->InsertVertex();
|
||||
auto e = dba->InsertEdge(v1, v2, dba->EdgeType("type1"));
|
||||
e.PropsSet(dba->Property("width"), 3);
|
||||
e.PropsSet(dba->Property("age"), 15);
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto v1 = dba.InsertVertex();
|
||||
v1.PropsSet(dba.Property("height"), 5);
|
||||
v1.PropsSet(dba.Property("age"), 10);
|
||||
auto v2 = dba.InsertVertex();
|
||||
auto e = dba.InsertEdge(v1, v2, dba.EdgeType("type1"));
|
||||
e.PropsSet(dba.Property("width"), 3);
|
||||
e.PropsSet(dba.Property("age"), 15);
|
||||
|
||||
auto prop_keys_to_string = [](TypedValue t) {
|
||||
std::vector<std::string> keys;
|
||||
@ -1175,49 +1174,49 @@ TEST(ExpressionEvaluator, ParameterLookup) {
|
||||
}
|
||||
|
||||
TEST(ExpressionEvaluator, FunctionCounter) {
|
||||
Dbms dbms;
|
||||
EXPECT_THROW(EvaluateFunction("COUNTER", {}, dbms), QueryRuntimeException);
|
||||
EXPECT_THROW(EvaluateFunction("COUNTER", {"a", "b"}, dbms),
|
||||
GraphDb db;
|
||||
EXPECT_THROW(EvaluateFunction("COUNTER", {}, db), QueryRuntimeException);
|
||||
EXPECT_THROW(EvaluateFunction("COUNTER", {"a", "b"}, db),
|
||||
QueryRuntimeException);
|
||||
EXPECT_EQ(EvaluateFunction("COUNTER", {"c1"}, dbms).ValueInt(), 0);
|
||||
EXPECT_EQ(EvaluateFunction("COUNTER", {"c1"}, dbms).ValueInt(), 1);
|
||||
EXPECT_EQ(EvaluateFunction("COUNTER", {"c2"}, dbms).ValueInt(), 0);
|
||||
EXPECT_EQ(EvaluateFunction("COUNTER", {"c1"}, dbms).ValueInt(), 2);
|
||||
EXPECT_EQ(EvaluateFunction("COUNTER", {"c2"}, dbms).ValueInt(), 1);
|
||||
EXPECT_EQ(EvaluateFunction("COUNTER", {"c1"}, db).ValueInt(), 0);
|
||||
EXPECT_EQ(EvaluateFunction("COUNTER", {"c1"}, db).ValueInt(), 1);
|
||||
EXPECT_EQ(EvaluateFunction("COUNTER", {"c2"}, db).ValueInt(), 0);
|
||||
EXPECT_EQ(EvaluateFunction("COUNTER", {"c1"}, db).ValueInt(), 2);
|
||||
EXPECT_EQ(EvaluateFunction("COUNTER", {"c2"}, db).ValueInt(), 1);
|
||||
}
|
||||
|
||||
TEST(ExpressionEvaluator, FunctionCounterSet) {
|
||||
Dbms dbms;
|
||||
EXPECT_THROW(EvaluateFunction("COUNTERSET", {}, dbms), QueryRuntimeException);
|
||||
EXPECT_THROW(EvaluateFunction("COUNTERSET", {"a"}, dbms),
|
||||
GraphDb db;
|
||||
EXPECT_THROW(EvaluateFunction("COUNTERSET", {}, db), QueryRuntimeException);
|
||||
EXPECT_THROW(EvaluateFunction("COUNTERSET", {"a"}, db),
|
||||
QueryRuntimeException);
|
||||
EXPECT_THROW(EvaluateFunction("COUNTERSET", {"a", "b"}, dbms),
|
||||
EXPECT_THROW(EvaluateFunction("COUNTERSET", {"a", "b"}, db),
|
||||
QueryRuntimeException);
|
||||
EXPECT_THROW(EvaluateFunction("COUNTERSET", {"a", 11, 12}, dbms),
|
||||
EXPECT_THROW(EvaluateFunction("COUNTERSET", {"a", 11, 12}, db),
|
||||
QueryRuntimeException);
|
||||
EXPECT_EQ(EvaluateFunction("COUNTER", {"c1"}, dbms).ValueInt(), 0);
|
||||
EvaluateFunction("COUNTERSET", {"c1", 12}, dbms);
|
||||
EXPECT_EQ(EvaluateFunction("COUNTER", {"c1"}, dbms).ValueInt(), 12);
|
||||
EvaluateFunction("COUNTERSET", {"c2", 42}, dbms);
|
||||
EXPECT_EQ(EvaluateFunction("COUNTER", {"c2"}, dbms).ValueInt(), 42);
|
||||
EXPECT_EQ(EvaluateFunction("COUNTER", {"c1"}, dbms).ValueInt(), 13);
|
||||
EXPECT_EQ(EvaluateFunction("COUNTER", {"c2"}, dbms).ValueInt(), 43);
|
||||
EXPECT_EQ(EvaluateFunction("COUNTER", {"c1"}, db).ValueInt(), 0);
|
||||
EvaluateFunction("COUNTERSET", {"c1", 12}, db);
|
||||
EXPECT_EQ(EvaluateFunction("COUNTER", {"c1"}, db).ValueInt(), 12);
|
||||
EvaluateFunction("COUNTERSET", {"c2", 42}, db);
|
||||
EXPECT_EQ(EvaluateFunction("COUNTER", {"c2"}, db).ValueInt(), 42);
|
||||
EXPECT_EQ(EvaluateFunction("COUNTER", {"c1"}, db).ValueInt(), 13);
|
||||
EXPECT_EQ(EvaluateFunction("COUNTER", {"c2"}, db).ValueInt(), 43);
|
||||
}
|
||||
|
||||
TEST(ExpressionEvaluator, FunctionIndexInfo) {
|
||||
Dbms dbms;
|
||||
EXPECT_THROW(EvaluateFunction("INDEXINFO", {1}, dbms), QueryRuntimeException);
|
||||
EXPECT_EQ(EvaluateFunction("INDEXINFO", {}, dbms).ValueList().size(), 0);
|
||||
auto dba = dbms.active();
|
||||
dba->InsertVertex().add_label(dba->Label("l1"));
|
||||
GraphDb db;
|
||||
EXPECT_THROW(EvaluateFunction("INDEXINFO", {1}, db), QueryRuntimeException);
|
||||
EXPECT_EQ(EvaluateFunction("INDEXINFO", {}, db).ValueList().size(), 0);
|
||||
GraphDbAccessor dba(db);
|
||||
dba.InsertVertex().add_label(dba.Label("l1"));
|
||||
{
|
||||
auto info = ToList<std::string>(EvaluateFunction("INDEXINFO", {}, dbms));
|
||||
auto info = ToList<std::string>(EvaluateFunction("INDEXINFO", {}, db));
|
||||
EXPECT_EQ(info.size(), 1);
|
||||
EXPECT_EQ(info[0], ":l1");
|
||||
}
|
||||
{
|
||||
dba->BuildIndex(dba->Label("l1"), dba->Property("prop"));
|
||||
auto info = ToList<std::string>(EvaluateFunction("INDEXINFO", {}, dbms));
|
||||
dba.BuildIndex(dba.Label("l1"), dba.Property("prop"));
|
||||
auto info = ToList<std::string>(EvaluateFunction("INDEXINFO", {}, db));
|
||||
EXPECT_EQ(info.size(), 2);
|
||||
EXPECT_THAT(info, testing::UnorderedElementsAre(":l1", ":l1(prop)"));
|
||||
}
|
||||
|
@ -12,7 +12,6 @@
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "communication/result_stream_faker.hpp"
|
||||
#include "database/dbms.hpp"
|
||||
#include "query/context.hpp"
|
||||
#include "query/exceptions.hpp"
|
||||
#include "query/plan/operator.hpp"
|
||||
@ -21,9 +20,9 @@
|
||||
|
||||
using namespace query;
|
||||
using namespace query::plan;
|
||||
using testing::UnorderedElementsAre;
|
||||
using query::test_common::ToList;
|
||||
using query::test_common::ToMap;
|
||||
using testing::UnorderedElementsAre;
|
||||
|
||||
TEST(QueryPlan, Accumulate) {
|
||||
// simulate the following two query execution on an empty db
|
||||
@ -33,16 +32,16 @@ TEST(QueryPlan, Accumulate) {
|
||||
// with accumulation we expect them to be [[2, 2], [2, 2]]
|
||||
|
||||
auto check = [&](bool accumulate) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto prop = dba->Property("x");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto prop = dba.Property("x");
|
||||
|
||||
auto v1 = dba->InsertVertex();
|
||||
auto v1 = dba.InsertVertex();
|
||||
v1.PropsSet(prop, 0);
|
||||
auto v2 = dba->InsertVertex();
|
||||
auto v2 = dba.InsertVertex();
|
||||
v2.PropsSet(prop, 0);
|
||||
dba->InsertEdge(v1, v2, dba->EdgeType("T"));
|
||||
dba->AdvanceCommand();
|
||||
dba.InsertEdge(v1, v2, dba.EdgeType("T"));
|
||||
dba.AdvanceCommand();
|
||||
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
@ -72,7 +71,7 @@ TEST(QueryPlan, Accumulate) {
|
||||
auto m_p_ne = NEXPR("m.p", m_p);
|
||||
symbol_table[*m_p_ne] = symbol_table.CreateSymbol("m_p_ne", true);
|
||||
auto produce = MakeProduce(last_op, n_p_ne, m_p_ne);
|
||||
auto results = CollectProduce(produce.get(), symbol_table, *dba);
|
||||
auto results = CollectProduce(produce.get(), symbol_table, dba);
|
||||
std::vector<int> results_data;
|
||||
for (const auto &row : results)
|
||||
for (const auto &column : row)
|
||||
@ -92,8 +91,8 @@ TEST(QueryPlan, AccumulateAdvance) {
|
||||
// to get correct results we need to advance the command
|
||||
|
||||
auto check = [&](bool advance) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
|
||||
@ -104,7 +103,7 @@ TEST(QueryPlan, AccumulateAdvance) {
|
||||
auto accumulate = std::make_shared<Accumulate>(
|
||||
create, std::vector<Symbol>{sym_n}, advance);
|
||||
auto match = MakeScanAll(storage, symbol_table, "m", accumulate);
|
||||
EXPECT_EQ(advance ? 1 : 0, PullAll(match.op_, *dba, symbol_table));
|
||||
EXPECT_EQ(advance ? 1 : 0, PullAll(match.op_, dba, symbol_table));
|
||||
};
|
||||
check(false);
|
||||
check(true);
|
||||
@ -154,9 +153,9 @@ std::shared_ptr<Produce> MakeAggregationProduce(
|
||||
/** Test fixture for all the aggregation ops in one return. */
|
||||
class QueryPlanAggregateOps : public ::testing::Test {
|
||||
protected:
|
||||
Dbms dbms;
|
||||
std::unique_ptr<GraphDbAccessor> dba = dbms.active();
|
||||
GraphDbTypes::Property prop = dba->Property("prop");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba{db};
|
||||
GraphDbTypes::Property prop = dba.Property("prop");
|
||||
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
@ -165,13 +164,13 @@ class QueryPlanAggregateOps : public ::testing::Test {
|
||||
// setup is several nodes most of which have an int property set
|
||||
// we will take the sum, avg, min, max and count
|
||||
// we won't group by anything
|
||||
dba->InsertVertex().PropsSet(prop, 5);
|
||||
dba->InsertVertex().PropsSet(prop, 7);
|
||||
dba->InsertVertex().PropsSet(prop, 12);
|
||||
dba.InsertVertex().PropsSet(prop, 5);
|
||||
dba.InsertVertex().PropsSet(prop, 7);
|
||||
dba.InsertVertex().PropsSet(prop, 12);
|
||||
// a missing property (null) gets ignored by all aggregations except
|
||||
// COUNT(*)
|
||||
dba->InsertVertex();
|
||||
dba->AdvanceCommand();
|
||||
dba.InsertVertex();
|
||||
dba.AdvanceCommand();
|
||||
}
|
||||
|
||||
auto AggregationResults(bool with_group_by,
|
||||
@ -193,7 +192,7 @@ class QueryPlanAggregateOps : public ::testing::Test {
|
||||
auto produce =
|
||||
MakeAggregationProduce(n.op_, symbol_table, storage,
|
||||
aggregation_expressions, ops, group_bys, {});
|
||||
return CollectProduce(produce.get(), symbol_table, *dba);
|
||||
return CollectProduce(produce.get(), symbol_table, dba);
|
||||
}
|
||||
};
|
||||
|
||||
@ -293,8 +292,8 @@ TEST(QueryPlan, AggregateGroupByValues) {
|
||||
// Tests that distinct groups are aggregated properly for values of all types.
|
||||
// Also test the "remember" part of the Aggregation API as final results are
|
||||
// obtained via a property lookup of a remembered node.
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
|
||||
// a vector of TypedValue to be set as property values on vertices
|
||||
// most of them should result in a distinct group (commented where not)
|
||||
@ -318,10 +317,10 @@ TEST(QueryPlan, AggregateGroupByValues) {
|
||||
group_by_vals.emplace_back(std::vector<TypedValue>{1, 2.0});
|
||||
|
||||
// generate a lot of vertices and set props on them
|
||||
auto prop = dba->Property("prop");
|
||||
auto prop = dba.Property("prop");
|
||||
for (int i = 0; i < 1000; ++i)
|
||||
dba->InsertVertex().PropsSet(prop, group_by_vals[i % group_by_vals.size()]);
|
||||
dba->AdvanceCommand();
|
||||
dba.InsertVertex().PropsSet(prop, group_by_vals[i % group_by_vals.size()]);
|
||||
dba.AdvanceCommand();
|
||||
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
@ -335,7 +334,7 @@ TEST(QueryPlan, AggregateGroupByValues) {
|
||||
MakeAggregationProduce(n.op_, symbol_table, storage, {n_p},
|
||||
{Aggregation::Op::COUNT}, {n_p}, {n.sym_});
|
||||
|
||||
auto results = CollectProduce(produce.get(), symbol_table, *dba);
|
||||
auto results = CollectProduce(produce.get(), symbol_table, dba);
|
||||
ASSERT_EQ(results.size(), group_by_vals.size() - 2);
|
||||
TypedValue::unordered_set result_group_bys;
|
||||
for (const auto &row : results) {
|
||||
@ -352,19 +351,19 @@ TEST(QueryPlan, AggregateMultipleGroupBy) {
|
||||
// in this test we have 3 different properties that have different values
|
||||
// for different records and assert that we get the correct combination
|
||||
// of values in our groups
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
|
||||
auto prop1 = dba->Property("prop1");
|
||||
auto prop2 = dba->Property("prop2");
|
||||
auto prop3 = dba->Property("prop3");
|
||||
auto prop1 = dba.Property("prop1");
|
||||
auto prop2 = dba.Property("prop2");
|
||||
auto prop3 = dba.Property("prop3");
|
||||
for (int i = 0; i < 2 * 3 * 5; ++i) {
|
||||
auto v = dba->InsertVertex();
|
||||
auto v = dba.InsertVertex();
|
||||
v.PropsSet(prop1, (bool)(i % 2));
|
||||
v.PropsSet(prop2, i % 3);
|
||||
v.PropsSet(prop3, "value" + std::to_string(i % 5));
|
||||
}
|
||||
dba->AdvanceCommand();
|
||||
dba.AdvanceCommand();
|
||||
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
@ -382,13 +381,13 @@ TEST(QueryPlan, AggregateMultipleGroupBy) {
|
||||
{Aggregation::Op::COUNT},
|
||||
{n_p1, n_p2, n_p3}, {n.sym_});
|
||||
|
||||
auto results = CollectProduce(produce.get(), symbol_table, *dba);
|
||||
auto results = CollectProduce(produce.get(), symbol_table, dba);
|
||||
EXPECT_EQ(results.size(), 2 * 3 * 5);
|
||||
}
|
||||
|
||||
TEST(QueryPlan, AggregateNoInput) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
|
||||
@ -398,7 +397,7 @@ TEST(QueryPlan, AggregateNoInput) {
|
||||
|
||||
auto produce = MakeAggregationProduce(nullptr, symbol_table, storage, {two},
|
||||
{Aggregation::Op::COUNT}, {}, {});
|
||||
auto results = CollectProduce(produce.get(), symbol_table, *dba);
|
||||
auto results = CollectProduce(produce.get(), symbol_table, dba);
|
||||
EXPECT_EQ(1, results.size());
|
||||
EXPECT_EQ(1, results[0].size());
|
||||
EXPECT_EQ(TypedValue::Type::Int, results[0][0].type());
|
||||
@ -414,9 +413,9 @@ TEST(QueryPlan, AggregateCountEdgeCases) {
|
||||
// - 2 vertices in database, property set on one
|
||||
// - 2 vertices in database, property set on both
|
||||
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto prop = dba->Property("prop");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto prop = dba.Property("prop");
|
||||
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
@ -430,7 +429,7 @@ TEST(QueryPlan, AggregateCountEdgeCases) {
|
||||
auto count = [&]() {
|
||||
auto produce = MakeAggregationProduce(n.op_, symbol_table, storage, {n_p},
|
||||
{Aggregation::Op::COUNT}, {}, {});
|
||||
auto results = CollectProduce(produce.get(), symbol_table, *dba);
|
||||
auto results = CollectProduce(produce.get(), symbol_table, dba);
|
||||
if (results.size() == 0) return -1L;
|
||||
EXPECT_EQ(1, results.size());
|
||||
EXPECT_EQ(1, results[0].size());
|
||||
@ -442,23 +441,23 @@ TEST(QueryPlan, AggregateCountEdgeCases) {
|
||||
EXPECT_EQ(0, count());
|
||||
|
||||
// one vertex, no property set
|
||||
dba->InsertVertex();
|
||||
dba->AdvanceCommand();
|
||||
dba.InsertVertex();
|
||||
dba.AdvanceCommand();
|
||||
EXPECT_EQ(0, count());
|
||||
|
||||
// one vertex, property set
|
||||
for (VertexAccessor va : dba->Vertices(false)) va.PropsSet(prop, 42);
|
||||
dba->AdvanceCommand();
|
||||
for (VertexAccessor va : dba.Vertices(false)) va.PropsSet(prop, 42);
|
||||
dba.AdvanceCommand();
|
||||
EXPECT_EQ(1, count());
|
||||
|
||||
// two vertices, one with property set
|
||||
dba->InsertVertex();
|
||||
dba->AdvanceCommand();
|
||||
dba.InsertVertex();
|
||||
dba.AdvanceCommand();
|
||||
EXPECT_EQ(1, count());
|
||||
|
||||
// two vertices, both with property set
|
||||
for (VertexAccessor va : dba->Vertices(false)) va.PropsSet(prop, 42);
|
||||
dba->AdvanceCommand();
|
||||
for (VertexAccessor va : dba.Vertices(false)) va.PropsSet(prop, 42);
|
||||
dba.AdvanceCommand();
|
||||
EXPECT_EQ(2, count());
|
||||
}
|
||||
|
||||
@ -466,15 +465,15 @@ TEST(QueryPlan, AggregateFirstValueTypes) {
|
||||
// testing exceptions that get emitted by the first-value
|
||||
// type check
|
||||
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
|
||||
auto v1 = dba->InsertVertex();
|
||||
auto prop_string = dba->Property("string");
|
||||
auto v1 = dba.InsertVertex();
|
||||
auto prop_string = dba.Property("string");
|
||||
v1.PropsSet(prop_string, "johhny");
|
||||
auto prop_int = dba->Property("int");
|
||||
auto prop_int = dba.Property("int");
|
||||
v1.PropsSet(prop_int, 12);
|
||||
dba->AdvanceCommand();
|
||||
dba.AdvanceCommand();
|
||||
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
@ -489,7 +488,7 @@ TEST(QueryPlan, AggregateFirstValueTypes) {
|
||||
auto aggregate = [&](Expression *expression, Aggregation::Op aggr_op) {
|
||||
auto produce = MakeAggregationProduce(n.op_, symbol_table, storage,
|
||||
{expression}, {aggr_op}, {}, {});
|
||||
CollectProduce(produce.get(), symbol_table, *dba);
|
||||
CollectProduce(produce.get(), symbol_table, dba);
|
||||
};
|
||||
|
||||
// everything except for COUNT and COLLECT fails on a Vertex
|
||||
@ -523,16 +522,16 @@ TEST(QueryPlan, AggregateTypes) {
|
||||
// does not check all combinations that can result in an exception
|
||||
// (that logic is defined and tested by TypedValue)
|
||||
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
|
||||
auto p1 = dba->Property("p1"); // has only string props
|
||||
dba->InsertVertex().PropsSet(p1, "string");
|
||||
dba->InsertVertex().PropsSet(p1, "str2");
|
||||
auto p2 = dba->Property("p2"); // combines int and bool
|
||||
dba->InsertVertex().PropsSet(p2, 42);
|
||||
dba->InsertVertex().PropsSet(p2, true);
|
||||
dba->AdvanceCommand();
|
||||
auto p1 = dba.Property("p1"); // has only string props
|
||||
dba.InsertVertex().PropsSet(p1, "string");
|
||||
dba.InsertVertex().PropsSet(p1, "str2");
|
||||
auto p2 = dba.Property("p2"); // combines int and bool
|
||||
dba.InsertVertex().PropsSet(p2, 42);
|
||||
dba.InsertVertex().PropsSet(p2, true);
|
||||
dba.AdvanceCommand();
|
||||
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
@ -546,7 +545,7 @@ TEST(QueryPlan, AggregateTypes) {
|
||||
auto aggregate = [&](Expression *expression, Aggregation::Op aggr_op) {
|
||||
auto produce = MakeAggregationProduce(n.op_, symbol_table, storage,
|
||||
{expression}, {aggr_op}, {}, {});
|
||||
CollectProduce(produce.get(), symbol_table, *dba);
|
||||
CollectProduce(produce.get(), symbol_table, dba);
|
||||
};
|
||||
|
||||
// everything except for COUNT and COLLECT fails on a Vertex
|
||||
@ -579,8 +578,8 @@ TEST(QueryPlan, AggregateTypes) {
|
||||
}
|
||||
|
||||
TEST(QueryPlan, Unwind) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
|
||||
@ -603,7 +602,7 @@ TEST(QueryPlan, Unwind) {
|
||||
symbol_table[*y_ne] = symbol_table.CreateSymbol("y_ne", true);
|
||||
auto produce = MakeProduce(unwind_1, x_ne, y_ne);
|
||||
|
||||
auto results = CollectProduce(produce.get(), symbol_table, *dba);
|
||||
auto results = CollectProduce(produce.get(), symbol_table, dba);
|
||||
ASSERT_EQ(4, results.size());
|
||||
const std::vector<int> expected_x_card{3, 3, 3, 1};
|
||||
auto expected_x_card_it = expected_x_card.begin();
|
||||
|
@ -12,7 +12,6 @@
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "communication/result_stream_faker.hpp"
|
||||
#include "database/dbms.hpp"
|
||||
#include "query/context.hpp"
|
||||
#include "query/exceptions.hpp"
|
||||
#include "query/plan/operator.hpp"
|
||||
@ -23,8 +22,8 @@ using namespace query;
|
||||
using namespace query::plan;
|
||||
|
||||
TEST(QueryPlan, Skip) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
@ -32,28 +31,28 @@ TEST(QueryPlan, Skip) {
|
||||
auto n = MakeScanAll(storage, symbol_table, "n1");
|
||||
auto skip = std::make_shared<plan::Skip>(n.op_, LITERAL(2));
|
||||
|
||||
EXPECT_EQ(0, PullAll(skip, *dba, symbol_table));
|
||||
EXPECT_EQ(0, PullAll(skip, dba, symbol_table));
|
||||
|
||||
dba->InsertVertex();
|
||||
dba->AdvanceCommand();
|
||||
EXPECT_EQ(0, PullAll(skip, *dba, symbol_table));
|
||||
dba.InsertVertex();
|
||||
dba.AdvanceCommand();
|
||||
EXPECT_EQ(0, PullAll(skip, dba, symbol_table));
|
||||
|
||||
dba->InsertVertex();
|
||||
dba->AdvanceCommand();
|
||||
EXPECT_EQ(0, PullAll(skip, *dba, symbol_table));
|
||||
dba.InsertVertex();
|
||||
dba.AdvanceCommand();
|
||||
EXPECT_EQ(0, PullAll(skip, dba, symbol_table));
|
||||
|
||||
dba->InsertVertex();
|
||||
dba->AdvanceCommand();
|
||||
EXPECT_EQ(1, PullAll(skip, *dba, symbol_table));
|
||||
dba.InsertVertex();
|
||||
dba.AdvanceCommand();
|
||||
EXPECT_EQ(1, PullAll(skip, dba, symbol_table));
|
||||
|
||||
for (int i = 0; i < 10; ++i) dba->InsertVertex();
|
||||
dba->AdvanceCommand();
|
||||
EXPECT_EQ(11, PullAll(skip, *dba, symbol_table));
|
||||
for (int i = 0; i < 10; ++i) dba.InsertVertex();
|
||||
dba.AdvanceCommand();
|
||||
EXPECT_EQ(11, PullAll(skip, dba, symbol_table));
|
||||
}
|
||||
|
||||
TEST(QueryPlan, Limit) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
@ -61,34 +60,34 @@ TEST(QueryPlan, Limit) {
|
||||
auto n = MakeScanAll(storage, symbol_table, "n1");
|
||||
auto skip = std::make_shared<plan::Limit>(n.op_, LITERAL(2));
|
||||
|
||||
EXPECT_EQ(0, PullAll(skip, *dba, symbol_table));
|
||||
EXPECT_EQ(0, PullAll(skip, dba, symbol_table));
|
||||
|
||||
dba->InsertVertex();
|
||||
dba->AdvanceCommand();
|
||||
EXPECT_EQ(1, PullAll(skip, *dba, symbol_table));
|
||||
dba.InsertVertex();
|
||||
dba.AdvanceCommand();
|
||||
EXPECT_EQ(1, PullAll(skip, dba, symbol_table));
|
||||
|
||||
dba->InsertVertex();
|
||||
dba->AdvanceCommand();
|
||||
EXPECT_EQ(2, PullAll(skip, *dba, symbol_table));
|
||||
dba.InsertVertex();
|
||||
dba.AdvanceCommand();
|
||||
EXPECT_EQ(2, PullAll(skip, dba, symbol_table));
|
||||
|
||||
dba->InsertVertex();
|
||||
dba->AdvanceCommand();
|
||||
EXPECT_EQ(2, PullAll(skip, *dba, symbol_table));
|
||||
dba.InsertVertex();
|
||||
dba.AdvanceCommand();
|
||||
EXPECT_EQ(2, PullAll(skip, dba, symbol_table));
|
||||
|
||||
for (int i = 0; i < 10; ++i) dba->InsertVertex();
|
||||
dba->AdvanceCommand();
|
||||
EXPECT_EQ(2, PullAll(skip, *dba, symbol_table));
|
||||
for (int i = 0; i < 10; ++i) dba.InsertVertex();
|
||||
dba.AdvanceCommand();
|
||||
EXPECT_EQ(2, PullAll(skip, dba, symbol_table));
|
||||
}
|
||||
|
||||
TEST(QueryPlan, CreateLimit) {
|
||||
// CREATE (n), (m)
|
||||
// MATCH (n) CREATE (m) LIMIT 1
|
||||
// in the end we need to have 3 vertices in the db
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
dba->InsertVertex();
|
||||
dba->InsertVertex();
|
||||
dba->AdvanceCommand();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
dba.InsertVertex();
|
||||
dba.InsertVertex();
|
||||
dba.AdvanceCommand();
|
||||
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
@ -99,17 +98,17 @@ TEST(QueryPlan, CreateLimit) {
|
||||
auto c = std::make_shared<CreateNode>(m, n.op_);
|
||||
auto skip = std::make_shared<plan::Limit>(c, LITERAL(1));
|
||||
|
||||
EXPECT_EQ(1, PullAll(skip, *dba, symbol_table));
|
||||
dba->AdvanceCommand();
|
||||
EXPECT_EQ(3, CountIterable(dba->Vertices(false)));
|
||||
EXPECT_EQ(1, PullAll(skip, dba, symbol_table));
|
||||
dba.AdvanceCommand();
|
||||
EXPECT_EQ(3, CountIterable(dba.Vertices(false)));
|
||||
}
|
||||
|
||||
TEST(QueryPlan, OrderBy) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
auto prop = dba->Property("prop");
|
||||
auto prop = dba.Property("prop");
|
||||
|
||||
// contains a series of tests
|
||||
// each test defines the ordering a vector of values in the desired order
|
||||
@ -125,9 +124,9 @@ TEST(QueryPlan, OrderBy) {
|
||||
for (const auto &order_value_pair : orderable) {
|
||||
const auto &values = order_value_pair.second;
|
||||
// empty database
|
||||
for (auto &vertex : dba->Vertices(false)) dba->DetachRemoveVertex(vertex);
|
||||
dba->AdvanceCommand();
|
||||
ASSERT_EQ(0, CountIterable(dba->Vertices(false)));
|
||||
for (auto &vertex : dba.Vertices(false)) dba.DetachRemoveVertex(vertex);
|
||||
dba.AdvanceCommand();
|
||||
ASSERT_EQ(0, CountIterable(dba.Vertices(false)));
|
||||
|
||||
// take some effort to shuffle the values
|
||||
// because we are testing that something not ordered gets ordered
|
||||
@ -144,8 +143,8 @@ TEST(QueryPlan, OrderBy) {
|
||||
|
||||
// create the vertices
|
||||
for (const auto &value : shuffled)
|
||||
dba->InsertVertex().PropsSet(prop, value);
|
||||
dba->AdvanceCommand();
|
||||
dba.InsertVertex().PropsSet(prop, value);
|
||||
dba.AdvanceCommand();
|
||||
|
||||
// order by and collect results
|
||||
auto n = MakeScanAll(storage, symbol_table, "n");
|
||||
@ -159,7 +158,7 @@ TEST(QueryPlan, OrderBy) {
|
||||
auto n_p_ne = NEXPR("n.p", n_p);
|
||||
symbol_table[*n_p_ne] = symbol_table.CreateSymbol("n.p", true);
|
||||
auto produce = MakeProduce(order_by, n_p_ne);
|
||||
auto results = CollectProduce(produce.get(), symbol_table, *dba);
|
||||
auto results = CollectProduce(produce.get(), symbol_table, dba);
|
||||
ASSERT_EQ(values.size(), results.size());
|
||||
for (int j = 0; j < results.size(); ++j)
|
||||
EXPECT_TRUE(TypedValue::BoolEqual{}(results[j][0], values[j]));
|
||||
@ -167,13 +166,13 @@ TEST(QueryPlan, OrderBy) {
|
||||
}
|
||||
|
||||
TEST(QueryPlan, OrderByMultiple) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
|
||||
auto p1 = dba->Property("p1");
|
||||
auto p2 = dba->Property("p2");
|
||||
auto p1 = dba.Property("p1");
|
||||
auto p2 = dba.Property("p2");
|
||||
|
||||
// create a bunch of vertices that in two properties
|
||||
// have all the variations (with repetition) of N values.
|
||||
@ -184,11 +183,11 @@ TEST(QueryPlan, OrderByMultiple) {
|
||||
for (int i = 0; i < N * N; ++i) prop_values.emplace_back(i % N, i / N);
|
||||
std::random_shuffle(prop_values.begin(), prop_values.end());
|
||||
for (const auto &pair : prop_values) {
|
||||
auto v = dba->InsertVertex();
|
||||
auto v = dba.InsertVertex();
|
||||
v.PropsSet(p1, pair.first);
|
||||
v.PropsSet(p2, pair.second);
|
||||
}
|
||||
dba->AdvanceCommand();
|
||||
dba.AdvanceCommand();
|
||||
|
||||
// order by and collect results
|
||||
auto n = MakeScanAll(storage, symbol_table, "n");
|
||||
@ -212,7 +211,7 @@ TEST(QueryPlan, OrderByMultiple) {
|
||||
auto n_p2_ne = NEXPR("n.p2", n_p2);
|
||||
symbol_table[*n_p2_ne] = symbol_table.CreateSymbol("n.p2", true);
|
||||
auto produce = MakeProduce(order_by, n_p1_ne, n_p2_ne);
|
||||
auto results = CollectProduce(produce.get(), symbol_table, *dba);
|
||||
auto results = CollectProduce(produce.get(), symbol_table, dba);
|
||||
ASSERT_EQ(N * N, results.size());
|
||||
for (int j = 0; j < N * N; ++j) {
|
||||
ASSERT_EQ(results[j][0].type(), TypedValue::Type::Int);
|
||||
@ -223,11 +222,11 @@ TEST(QueryPlan, OrderByMultiple) {
|
||||
}
|
||||
|
||||
TEST(QueryPlan, OrderByExceptions) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
auto prop = dba->Property("prop");
|
||||
auto prop = dba.Property("prop");
|
||||
|
||||
// a vector of pairs of typed values that should result
|
||||
// in an exception when trying to order on them
|
||||
@ -243,16 +242,16 @@ TEST(QueryPlan, OrderByExceptions) {
|
||||
|
||||
for (const auto &pair : exception_pairs) {
|
||||
// empty database
|
||||
for (auto &vertex : dba->Vertices(false)) dba->DetachRemoveVertex(vertex);
|
||||
dba->AdvanceCommand();
|
||||
ASSERT_EQ(0, CountIterable(dba->Vertices(false)));
|
||||
for (auto &vertex : dba.Vertices(false)) dba.DetachRemoveVertex(vertex);
|
||||
dba.AdvanceCommand();
|
||||
ASSERT_EQ(0, CountIterable(dba.Vertices(false)));
|
||||
|
||||
// make two vertices, and set values
|
||||
dba->InsertVertex().PropsSet(prop, pair.first);
|
||||
dba->InsertVertex().PropsSet(prop, pair.second);
|
||||
dba->AdvanceCommand();
|
||||
ASSERT_EQ(2, CountIterable(dba->Vertices(false)));
|
||||
for (const auto &va : dba->Vertices(false))
|
||||
dba.InsertVertex().PropsSet(prop, pair.first);
|
||||
dba.InsertVertex().PropsSet(prop, pair.second);
|
||||
dba.AdvanceCommand();
|
||||
ASSERT_EQ(2, CountIterable(dba.Vertices(false)));
|
||||
for (const auto &va : dba.Vertices(false))
|
||||
ASSERT_NE(va.PropsAt(prop).type(), PropertyValue::Type::Null);
|
||||
|
||||
// order by and expect an exception
|
||||
@ -263,6 +262,6 @@ TEST(QueryPlan, OrderByExceptions) {
|
||||
n.op_,
|
||||
std::vector<std::pair<Ordering, Expression *>>{{Ordering::ASC, n_p}},
|
||||
std::vector<Symbol>{});
|
||||
EXPECT_THROW(PullAll(order_by, *dba, symbol_table), QueryRuntimeException);
|
||||
EXPECT_THROW(PullAll(order_by, dba, symbol_table), QueryRuntimeException);
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,6 @@
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "communication/result_stream_faker.hpp"
|
||||
#include "database/dbms.hpp"
|
||||
#include "query/context.hpp"
|
||||
#include "query/exceptions.hpp"
|
||||
#include "query/interpret/frame.hpp"
|
||||
@ -23,10 +22,10 @@ using namespace query;
|
||||
using namespace query::plan;
|
||||
|
||||
TEST(QueryPlan, CreateNodeWithAttributes) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
|
||||
GraphDbTypes::Label label = dba->Label("Person");
|
||||
GraphDbTypes::Label label = dba.Label("Person");
|
||||
auto property = PROPERTY_PAIR("prop");
|
||||
|
||||
AstTreeStorage storage;
|
||||
@ -38,12 +37,12 @@ TEST(QueryPlan, CreateNodeWithAttributes) {
|
||||
node->properties_[property] = LITERAL(42);
|
||||
|
||||
auto create = std::make_shared<CreateNode>(node, nullptr);
|
||||
PullAll(create, *dba, symbol_table);
|
||||
dba->AdvanceCommand();
|
||||
PullAll(create, dba, symbol_table);
|
||||
dba.AdvanceCommand();
|
||||
|
||||
// count the number of vertices
|
||||
int vertex_count = 0;
|
||||
for (VertexAccessor vertex : dba->Vertices(false)) {
|
||||
for (VertexAccessor vertex : dba.Vertices(false)) {
|
||||
vertex_count++;
|
||||
EXPECT_EQ(vertex.labels().size(), 1);
|
||||
EXPECT_EQ(*vertex.labels().begin(), label);
|
||||
@ -57,10 +56,10 @@ TEST(QueryPlan, CreateNodeWithAttributes) {
|
||||
|
||||
TEST(QueryPlan, CreateReturn) {
|
||||
// test CREATE (n:Person {age: 42}) RETURN n, n.age
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
|
||||
GraphDbTypes::Label label = dba->Label("Person");
|
||||
GraphDbTypes::Label label = dba.Label("Person");
|
||||
auto property = PROPERTY_PAIR("property");
|
||||
|
||||
AstTreeStorage storage;
|
||||
@ -84,7 +83,7 @@ TEST(QueryPlan, CreateReturn) {
|
||||
symbol_table[*named_expr_n->expression_] = sym_n;
|
||||
|
||||
auto produce = MakeProduce(create, named_expr_n, named_expr_n_p);
|
||||
auto results = CollectProduce(produce.get(), symbol_table, *dba);
|
||||
auto results = CollectProduce(produce.get(), symbol_table, dba);
|
||||
EXPECT_EQ(1, results.size());
|
||||
EXPECT_EQ(2, results[0].size());
|
||||
EXPECT_EQ(TypedValue::Type::Vertex, results[0][0].type());
|
||||
@ -93,26 +92,26 @@ TEST(QueryPlan, CreateReturn) {
|
||||
EXPECT_EQ(TypedValue::Type::Int, results[0][1].type());
|
||||
EXPECT_EQ(42, results[0][1].Value<int64_t>());
|
||||
|
||||
dba->AdvanceCommand();
|
||||
EXPECT_EQ(1, CountIterable(dba->Vertices(false)));
|
||||
dba.AdvanceCommand();
|
||||
EXPECT_EQ(1, CountIterable(dba.Vertices(false)));
|
||||
}
|
||||
|
||||
TEST(QueryPlan, CreateExpand) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
|
||||
GraphDbTypes::Label label_node_1 = dba->Label("Node1");
|
||||
GraphDbTypes::Label label_node_2 = dba->Label("Node2");
|
||||
GraphDbTypes::Label label_node_1 = dba.Label("Node1");
|
||||
GraphDbTypes::Label label_node_2 = dba.Label("Node2");
|
||||
auto property = PROPERTY_PAIR("property");
|
||||
GraphDbTypes::EdgeType edge_type = dba->Label("edge_type");
|
||||
GraphDbTypes::EdgeType edge_type = dba.Label("edge_type");
|
||||
|
||||
SymbolTable symbol_table;
|
||||
AstTreeStorage storage;
|
||||
|
||||
auto test_create_path = [&](bool cycle, int expected_nodes_created,
|
||||
int expected_edges_created) {
|
||||
int before_v = CountIterable(dba->Vertices(false));
|
||||
int before_e = CountIterable(dba->Edges(false));
|
||||
int before_v = CountIterable(dba.Vertices(false));
|
||||
int before_e = CountIterable(dba.Edges(false));
|
||||
|
||||
// data for the first node
|
||||
auto n = NODE("n");
|
||||
@ -138,19 +137,19 @@ TEST(QueryPlan, CreateExpand) {
|
||||
auto create_op = std::make_shared<CreateNode>(n, nullptr);
|
||||
auto create_expand =
|
||||
std::make_shared<CreateExpand>(m, r, create_op, n_sym, cycle);
|
||||
PullAll(create_expand, *dba, symbol_table);
|
||||
dba->AdvanceCommand();
|
||||
PullAll(create_expand, dba, symbol_table);
|
||||
dba.AdvanceCommand();
|
||||
|
||||
EXPECT_EQ(CountIterable(dba->Vertices(false)) - before_v,
|
||||
EXPECT_EQ(CountIterable(dba.Vertices(false)) - before_v,
|
||||
expected_nodes_created);
|
||||
EXPECT_EQ(CountIterable(dba->Edges(false)) - before_e,
|
||||
EXPECT_EQ(CountIterable(dba.Edges(false)) - before_e,
|
||||
expected_edges_created);
|
||||
};
|
||||
|
||||
test_create_path(false, 2, 1);
|
||||
test_create_path(true, 1, 1);
|
||||
|
||||
for (VertexAccessor vertex : dba->Vertices(false)) {
|
||||
for (VertexAccessor vertex : dba.Vertices(false)) {
|
||||
EXPECT_EQ(vertex.labels().size(), 1);
|
||||
GraphDbTypes::Label label = vertex.labels()[0];
|
||||
if (label == label_node_1) {
|
||||
@ -164,7 +163,7 @@ TEST(QueryPlan, CreateExpand) {
|
||||
FAIL();
|
||||
}
|
||||
|
||||
for (EdgeAccessor edge : dba->Edges(false)) {
|
||||
for (EdgeAccessor edge : dba.Edges(false)) {
|
||||
EXPECT_EQ(edge.EdgeType(), edge_type);
|
||||
EXPECT_EQ(edge.PropsAt(property.second).Value<int64_t>(), 3);
|
||||
}
|
||||
@ -172,14 +171,14 @@ TEST(QueryPlan, CreateExpand) {
|
||||
}
|
||||
|
||||
TEST(QueryPlan, MatchCreateNode) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
|
||||
// add three nodes we'll match and expand-create from
|
||||
dba->InsertVertex();
|
||||
dba->InsertVertex();
|
||||
dba->InsertVertex();
|
||||
dba->AdvanceCommand();
|
||||
dba.InsertVertex();
|
||||
dba.InsertVertex();
|
||||
dba.InsertVertex();
|
||||
dba.AdvanceCommand();
|
||||
|
||||
SymbolTable symbol_table;
|
||||
AstTreeStorage storage;
|
||||
@ -192,34 +191,34 @@ TEST(QueryPlan, MatchCreateNode) {
|
||||
// creation op
|
||||
auto create_node = std::make_shared<CreateNode>(m, n_scan_all.op_);
|
||||
|
||||
EXPECT_EQ(CountIterable(dba->Vertices(false)), 3);
|
||||
PullAll(create_node, *dba, symbol_table);
|
||||
dba->AdvanceCommand();
|
||||
EXPECT_EQ(CountIterable(dba->Vertices(false)), 6);
|
||||
EXPECT_EQ(CountIterable(dba.Vertices(false)), 3);
|
||||
PullAll(create_node, dba, symbol_table);
|
||||
dba.AdvanceCommand();
|
||||
EXPECT_EQ(CountIterable(dba.Vertices(false)), 6);
|
||||
}
|
||||
|
||||
TEST(QueryPlan, MatchCreateExpand) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
|
||||
// add three nodes we'll match and expand-create from
|
||||
dba->InsertVertex();
|
||||
dba->InsertVertex();
|
||||
dba->InsertVertex();
|
||||
dba->AdvanceCommand();
|
||||
dba.InsertVertex();
|
||||
dba.InsertVertex();
|
||||
dba.InsertVertex();
|
||||
dba.AdvanceCommand();
|
||||
|
||||
// GraphDbTypes::Label label_node_1 = dba->Label("Node1");
|
||||
// GraphDbTypes::Label label_node_2 = dba->Label("Node2");
|
||||
// GraphDbTypes::Property property = dba->Label("prop");
|
||||
GraphDbTypes::EdgeType edge_type = dba->Label("edge_type");
|
||||
// GraphDbTypes::Label label_node_1 = dba.Label("Node1");
|
||||
// GraphDbTypes::Label label_node_2 = dba.Label("Node2");
|
||||
// GraphDbTypes::Property property = dba.Label("prop");
|
||||
GraphDbTypes::EdgeType edge_type = dba.Label("edge_type");
|
||||
|
||||
SymbolTable symbol_table;
|
||||
AstTreeStorage storage;
|
||||
|
||||
auto test_create_path = [&](bool cycle, int expected_nodes_created,
|
||||
int expected_edges_created) {
|
||||
int before_v = CountIterable(dba->Vertices(false));
|
||||
int before_e = CountIterable(dba->Edges(false));
|
||||
int before_v = CountIterable(dba.Vertices(false));
|
||||
int before_e = CountIterable(dba.Edges(false));
|
||||
|
||||
// data for the first node
|
||||
auto n_scan_all = MakeScanAll(storage, symbol_table, "n");
|
||||
@ -237,12 +236,12 @@ TEST(QueryPlan, MatchCreateExpand) {
|
||||
|
||||
auto create_expand = std::make_shared<CreateExpand>(m, r, n_scan_all.op_,
|
||||
n_scan_all.sym_, cycle);
|
||||
PullAll(create_expand, *dba, symbol_table);
|
||||
dba->AdvanceCommand();
|
||||
PullAll(create_expand, dba, symbol_table);
|
||||
dba.AdvanceCommand();
|
||||
|
||||
EXPECT_EQ(CountIterable(dba->Vertices(false)) - before_v,
|
||||
EXPECT_EQ(CountIterable(dba.Vertices(false)) - before_v,
|
||||
expected_nodes_created);
|
||||
EXPECT_EQ(CountIterable(dba->Edges(false)) - before_e,
|
||||
EXPECT_EQ(CountIterable(dba.Edges(false)) - before_e,
|
||||
expected_edges_created);
|
||||
};
|
||||
|
||||
@ -251,20 +250,20 @@ TEST(QueryPlan, MatchCreateExpand) {
|
||||
}
|
||||
|
||||
TEST(QueryPlan, Delete) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
|
||||
// make a fully-connected (one-direction, no cycles) with 4 nodes
|
||||
std::vector<VertexAccessor> vertices;
|
||||
for (int i = 0; i < 4; ++i) vertices.push_back(dba->InsertVertex());
|
||||
auto type = dba->EdgeType("type");
|
||||
for (int i = 0; i < 4; ++i) vertices.push_back(dba.InsertVertex());
|
||||
auto type = dba.EdgeType("type");
|
||||
for (int j = 0; j < 4; ++j)
|
||||
for (int k = j + 1; k < 4; ++k)
|
||||
dba->InsertEdge(vertices[j], vertices[k], type);
|
||||
dba.InsertEdge(vertices[j], vertices[k], type);
|
||||
|
||||
dba->AdvanceCommand();
|
||||
EXPECT_EQ(4, CountIterable(dba->Vertices(false)));
|
||||
EXPECT_EQ(6, CountIterable(dba->Edges(false)));
|
||||
dba.AdvanceCommand();
|
||||
EXPECT_EQ(4, CountIterable(dba.Vertices(false)));
|
||||
EXPECT_EQ(6, CountIterable(dba.Edges(false)));
|
||||
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
@ -276,10 +275,10 @@ TEST(QueryPlan, Delete) {
|
||||
symbol_table[*n_get] = n.sym_;
|
||||
auto delete_op = std::make_shared<plan::Delete>(
|
||||
n.op_, std::vector<Expression *>{n_get}, false);
|
||||
EXPECT_THROW(PullAll(delete_op, *dba, symbol_table), QueryRuntimeException);
|
||||
dba->AdvanceCommand();
|
||||
EXPECT_EQ(4, CountIterable(dba->Vertices(false)));
|
||||
EXPECT_EQ(6, CountIterable(dba->Edges(false)));
|
||||
EXPECT_THROW(PullAll(delete_op, dba, symbol_table), QueryRuntimeException);
|
||||
dba.AdvanceCommand();
|
||||
EXPECT_EQ(4, CountIterable(dba.Vertices(false)));
|
||||
EXPECT_EQ(6, CountIterable(dba.Edges(false)));
|
||||
}
|
||||
|
||||
// detach delete a single vertex
|
||||
@ -290,12 +289,12 @@ TEST(QueryPlan, Delete) {
|
||||
auto delete_op = std::make_shared<plan::Delete>(
|
||||
n.op_, std::vector<Expression *>{n_get}, true);
|
||||
Frame frame(symbol_table.max_position());
|
||||
Context context(*dba);
|
||||
Context context(dba);
|
||||
context.symbol_table_ = symbol_table;
|
||||
delete_op->MakeCursor(*dba)->Pull(frame, context);
|
||||
dba->AdvanceCommand();
|
||||
EXPECT_EQ(3, CountIterable(dba->Vertices(false)));
|
||||
EXPECT_EQ(3, CountIterable(dba->Edges(false)));
|
||||
delete_op->MakeCursor(dba)->Pull(frame, context);
|
||||
dba.AdvanceCommand();
|
||||
EXPECT_EQ(3, CountIterable(dba.Vertices(false)));
|
||||
EXPECT_EQ(3, CountIterable(dba.Edges(false)));
|
||||
}
|
||||
|
||||
// delete all remaining edges
|
||||
@ -307,10 +306,10 @@ TEST(QueryPlan, Delete) {
|
||||
symbol_table[*r_get] = r_m.edge_sym_;
|
||||
auto delete_op = std::make_shared<plan::Delete>(
|
||||
r_m.op_, std::vector<Expression *>{r_get}, false);
|
||||
PullAll(delete_op, *dba, symbol_table);
|
||||
dba->AdvanceCommand();
|
||||
EXPECT_EQ(3, CountIterable(dba->Vertices(false)));
|
||||
EXPECT_EQ(0, CountIterable(dba->Edges(false)));
|
||||
PullAll(delete_op, dba, symbol_table);
|
||||
dba.AdvanceCommand();
|
||||
EXPECT_EQ(3, CountIterable(dba.Vertices(false)));
|
||||
EXPECT_EQ(0, CountIterable(dba.Edges(false)));
|
||||
}
|
||||
|
||||
// delete all remaining vertices
|
||||
@ -320,10 +319,10 @@ TEST(QueryPlan, Delete) {
|
||||
symbol_table[*n_get] = n.sym_;
|
||||
auto delete_op = std::make_shared<plan::Delete>(
|
||||
n.op_, std::vector<Expression *>{n_get}, false);
|
||||
PullAll(delete_op, *dba, symbol_table);
|
||||
dba->AdvanceCommand();
|
||||
EXPECT_EQ(0, CountIterable(dba->Vertices(false)));
|
||||
EXPECT_EQ(0, CountIterable(dba->Edges(false)));
|
||||
PullAll(delete_op, dba, symbol_table);
|
||||
dba.AdvanceCommand();
|
||||
EXPECT_EQ(0, CountIterable(dba.Vertices(false)));
|
||||
EXPECT_EQ(0, CountIterable(dba.Edges(false)));
|
||||
}
|
||||
}
|
||||
|
||||
@ -340,15 +339,15 @@ TEST(QueryPlan, DeleteTwiceDeleteBlockingEdge) {
|
||||
// MATCH (n)-[r]-(m) [DETACH] DELETE n, r, m
|
||||
|
||||
auto test_delete = [](bool detach) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
|
||||
auto v1 = dba->InsertVertex();
|
||||
auto v2 = dba->InsertVertex();
|
||||
dba->InsertEdge(v1, v2, dba->EdgeType("T"));
|
||||
dba->AdvanceCommand();
|
||||
EXPECT_EQ(2, CountIterable(dba->Vertices(false)));
|
||||
EXPECT_EQ(1, CountIterable(dba->Edges(false)));
|
||||
auto v1 = dba.InsertVertex();
|
||||
auto v2 = dba.InsertVertex();
|
||||
dba.InsertEdge(v1, v2, dba.EdgeType("T"));
|
||||
dba.AdvanceCommand();
|
||||
EXPECT_EQ(2, CountIterable(dba.Vertices(false)));
|
||||
EXPECT_EQ(1, CountIterable(dba.Edges(false)));
|
||||
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
@ -367,10 +366,10 @@ TEST(QueryPlan, DeleteTwiceDeleteBlockingEdge) {
|
||||
|
||||
auto delete_op = std::make_shared<plan::Delete>(
|
||||
r_m.op_, std::vector<Expression *>{n_get, r_get, m_get}, detach);
|
||||
EXPECT_EQ(2, PullAll(delete_op, *dba, symbol_table));
|
||||
dba->AdvanceCommand();
|
||||
EXPECT_EQ(0, CountIterable(dba->Vertices(false)));
|
||||
EXPECT_EQ(0, CountIterable(dba->Edges(false)));
|
||||
EXPECT_EQ(2, PullAll(delete_op, dba, symbol_table));
|
||||
dba.AdvanceCommand();
|
||||
EXPECT_EQ(0, CountIterable(dba.Vertices(false)));
|
||||
EXPECT_EQ(0, CountIterable(dba.Edges(false)));
|
||||
};
|
||||
|
||||
test_delete(true);
|
||||
@ -378,19 +377,19 @@ TEST(QueryPlan, DeleteTwiceDeleteBlockingEdge) {
|
||||
}
|
||||
|
||||
TEST(QueryPlan, DeleteReturn) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
|
||||
// make a fully-connected (one-direction, no cycles) with 4 nodes
|
||||
auto prop = PROPERTY_PAIR("property");
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
auto va = dba->InsertVertex();
|
||||
auto va = dba.InsertVertex();
|
||||
va.PropsSet(prop.second, 42);
|
||||
}
|
||||
|
||||
dba->AdvanceCommand();
|
||||
EXPECT_EQ(4, CountIterable(dba->Vertices(false)));
|
||||
EXPECT_EQ(0, CountIterable(dba->Edges(false)));
|
||||
dba.AdvanceCommand();
|
||||
EXPECT_EQ(4, CountIterable(dba.Vertices(false)));
|
||||
EXPECT_EQ(0, CountIterable(dba.Edges(false)));
|
||||
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
@ -409,23 +408,23 @@ TEST(QueryPlan, DeleteReturn) {
|
||||
symbol_table[*n_p] = symbol_table.CreateSymbol("bla", true);
|
||||
auto produce = MakeProduce(delete_op, n_p);
|
||||
|
||||
auto results = CollectProduce(produce.get(), symbol_table, *dba);
|
||||
auto results = CollectProduce(produce.get(), symbol_table, dba);
|
||||
EXPECT_EQ(4, results.size());
|
||||
dba->AdvanceCommand();
|
||||
EXPECT_EQ(0, CountIterable(dba->Vertices(false)));
|
||||
dba.AdvanceCommand();
|
||||
EXPECT_EQ(0, CountIterable(dba.Vertices(false)));
|
||||
}
|
||||
|
||||
TEST(QueryPlan, DeleteNull) {
|
||||
// test (simplified) WITH Null as x delete x
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
|
||||
auto once = std::make_shared<Once>();
|
||||
auto delete_op = std::make_shared<plan::Delete>(
|
||||
once, std::vector<Expression *>{LITERAL(TypedValue::Null)}, false);
|
||||
EXPECT_EQ(1, PullAll(delete_op, *dba, symbol_table));
|
||||
EXPECT_EQ(1, PullAll(delete_op, dba, symbol_table));
|
||||
}
|
||||
|
||||
TEST(QueryPlan, DeleteAdvance) {
|
||||
@ -438,10 +437,10 @@ TEST(QueryPlan, DeleteAdvance) {
|
||||
// note that Neo does not fail when the deleted
|
||||
// record is not used in subsequent clauses, but
|
||||
// we are not yet compatible with that
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
dba->InsertVertex();
|
||||
dba->AdvanceCommand();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
dba.InsertVertex();
|
||||
dba.AdvanceCommand();
|
||||
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
@ -453,24 +452,24 @@ TEST(QueryPlan, DeleteAdvance) {
|
||||
n.op_, std::vector<Expression *>{n_get}, false);
|
||||
auto advance = std::make_shared<Accumulate>(
|
||||
delete_op, std::vector<Symbol>{n.sym_}, true);
|
||||
EXPECT_THROW(PullAll(advance, *dba, symbol_table), QueryRuntimeException);
|
||||
EXPECT_THROW(PullAll(advance, dba, symbol_table), QueryRuntimeException);
|
||||
}
|
||||
|
||||
TEST(QueryPlan, SetProperty) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
|
||||
// graph with 4 vertices in connected pairs
|
||||
// the origin vertex in each par and both edges
|
||||
// have a property set
|
||||
auto v1 = dba->InsertVertex();
|
||||
auto v2 = dba->InsertVertex();
|
||||
auto v3 = dba->InsertVertex();
|
||||
auto v4 = dba->InsertVertex();
|
||||
auto edge_type = dba->EdgeType("edge_type");
|
||||
dba->InsertEdge(v1, v3, edge_type);
|
||||
dba->InsertEdge(v2, v4, edge_type);
|
||||
dba->AdvanceCommand();
|
||||
auto v1 = dba.InsertVertex();
|
||||
auto v2 = dba.InsertVertex();
|
||||
auto v3 = dba.InsertVertex();
|
||||
auto v4 = dba.InsertVertex();
|
||||
auto edge_type = dba.EdgeType("edge_type");
|
||||
dba.InsertEdge(v1, v3, edge_type);
|
||||
dba.InsertEdge(v2, v4, edge_type);
|
||||
dba.AdvanceCommand();
|
||||
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
@ -481,7 +480,7 @@ TEST(QueryPlan, SetProperty) {
|
||||
EdgeAtom::Direction::OUT, {}, "m", false);
|
||||
|
||||
// set prop1 to 42 on n and r
|
||||
auto prop1 = dba->Property("prop1");
|
||||
auto prop1 = dba.Property("prop1");
|
||||
auto literal = LITERAL(42);
|
||||
|
||||
auto n_p = PROPERTY_LOOKUP("n", prop1);
|
||||
@ -491,11 +490,11 @@ TEST(QueryPlan, SetProperty) {
|
||||
auto r_p = PROPERTY_LOOKUP("r", prop1);
|
||||
symbol_table[*r_p->expression_] = r_m.edge_sym_;
|
||||
auto set_r_p = std::make_shared<plan::SetProperty>(set_n_p, r_p, literal);
|
||||
EXPECT_EQ(2, PullAll(set_r_p, *dba, symbol_table));
|
||||
dba->AdvanceCommand();
|
||||
EXPECT_EQ(2, PullAll(set_r_p, dba, symbol_table));
|
||||
dba.AdvanceCommand();
|
||||
|
||||
EXPECT_EQ(CountIterable(dba->Edges(false)), 2);
|
||||
for (EdgeAccessor edge : dba->Edges(false)) {
|
||||
EXPECT_EQ(CountIterable(dba.Edges(false)), 2);
|
||||
for (EdgeAccessor edge : dba.Edges(false)) {
|
||||
ASSERT_EQ(edge.PropsAt(prop1).type(), PropertyValue::Type::Int);
|
||||
EXPECT_EQ(edge.PropsAt(prop1).Value<int64_t>(), 42);
|
||||
VertexAccessor from = edge.from();
|
||||
@ -508,20 +507,20 @@ TEST(QueryPlan, SetProperty) {
|
||||
|
||||
TEST(QueryPlan, SetProperties) {
|
||||
auto test_set_properties = [](bool update) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
|
||||
// graph: ({a: 0})-[:R {b:1}]->({c:2})
|
||||
auto prop_a = dba->Property("a");
|
||||
auto prop_b = dba->Property("b");
|
||||
auto prop_c = dba->Property("c");
|
||||
auto v1 = dba->InsertVertex();
|
||||
auto v2 = dba->InsertVertex();
|
||||
auto e = dba->InsertEdge(v1, v2, dba->EdgeType("R"));
|
||||
auto prop_a = dba.Property("a");
|
||||
auto prop_b = dba.Property("b");
|
||||
auto prop_c = dba.Property("c");
|
||||
auto v1 = dba.InsertVertex();
|
||||
auto v2 = dba.InsertVertex();
|
||||
auto e = dba.InsertEdge(v1, v2, dba.EdgeType("R"));
|
||||
v1.PropsSet(prop_a, 0);
|
||||
e.PropsSet(prop_b, 1);
|
||||
v2.PropsSet(prop_c, 2);
|
||||
dba->AdvanceCommand();
|
||||
dba.AdvanceCommand();
|
||||
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
@ -543,11 +542,11 @@ TEST(QueryPlan, SetProperties) {
|
||||
std::make_shared<plan::SetProperties>(r_m.op_, n.sym_, r_ident, op);
|
||||
auto set_m_to_r = std::make_shared<plan::SetProperties>(
|
||||
set_r_to_n, r_m.edge_sym_, m_ident, op);
|
||||
EXPECT_EQ(1, PullAll(set_m_to_r, *dba, symbol_table));
|
||||
dba->AdvanceCommand();
|
||||
EXPECT_EQ(1, PullAll(set_m_to_r, dba, symbol_table));
|
||||
dba.AdvanceCommand();
|
||||
|
||||
EXPECT_EQ(CountIterable(dba->Edges(false)), 1);
|
||||
for (EdgeAccessor edge : dba->Edges(false)) {
|
||||
EXPECT_EQ(CountIterable(dba.Edges(false)), 1);
|
||||
for (EdgeAccessor edge : dba.Edges(false)) {
|
||||
VertexAccessor from = edge.from();
|
||||
EXPECT_EQ(from.Properties().size(), update ? 2 : 1);
|
||||
if (update) {
|
||||
@ -577,15 +576,15 @@ TEST(QueryPlan, SetProperties) {
|
||||
}
|
||||
|
||||
TEST(QueryPlan, SetLabels) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
|
||||
auto label1 = dba->Label("label1");
|
||||
auto label2 = dba->Label("label2");
|
||||
auto label3 = dba->Label("label3");
|
||||
dba->InsertVertex().add_label(label1);
|
||||
dba->InsertVertex().add_label(label1);
|
||||
dba->AdvanceCommand();
|
||||
auto label1 = dba.Label("label1");
|
||||
auto label2 = dba.Label("label2");
|
||||
auto label3 = dba.Label("label3");
|
||||
dba.InsertVertex().add_label(label1);
|
||||
dba.InsertVertex().add_label(label1);
|
||||
dba.AdvanceCommand();
|
||||
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
@ -593,9 +592,9 @@ TEST(QueryPlan, SetLabels) {
|
||||
auto n = MakeScanAll(storage, symbol_table, "n");
|
||||
auto label_set = std::make_shared<plan::SetLabels>(
|
||||
n.op_, n.sym_, std::vector<GraphDbTypes::Label>{label2, label3});
|
||||
EXPECT_EQ(2, PullAll(label_set, *dba, symbol_table));
|
||||
EXPECT_EQ(2, PullAll(label_set, dba, symbol_table));
|
||||
|
||||
for (VertexAccessor vertex : dba->Vertices(false)) {
|
||||
for (VertexAccessor vertex : dba.Vertices(false)) {
|
||||
vertex.SwitchNew();
|
||||
EXPECT_EQ(3, vertex.labels().size());
|
||||
EXPECT_TRUE(vertex.has_label(label2));
|
||||
@ -604,27 +603,27 @@ TEST(QueryPlan, SetLabels) {
|
||||
}
|
||||
|
||||
TEST(QueryPlan, RemoveProperty) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
|
||||
// graph with 4 vertices in connected pairs
|
||||
// the origin vertex in each par and both edges
|
||||
// have a property set
|
||||
auto prop1 = dba->Property("prop1");
|
||||
auto v1 = dba->InsertVertex();
|
||||
auto v2 = dba->InsertVertex();
|
||||
auto v3 = dba->InsertVertex();
|
||||
auto v4 = dba->InsertVertex();
|
||||
auto edge_type = dba->EdgeType("edge_type");
|
||||
dba->InsertEdge(v1, v3, edge_type).PropsSet(prop1, 42);
|
||||
dba->InsertEdge(v2, v4, edge_type);
|
||||
auto prop1 = dba.Property("prop1");
|
||||
auto v1 = dba.InsertVertex();
|
||||
auto v2 = dba.InsertVertex();
|
||||
auto v3 = dba.InsertVertex();
|
||||
auto v4 = dba.InsertVertex();
|
||||
auto edge_type = dba.EdgeType("edge_type");
|
||||
dba.InsertEdge(v1, v3, edge_type).PropsSet(prop1, 42);
|
||||
dba.InsertEdge(v2, v4, edge_type);
|
||||
v2.PropsSet(prop1, 42);
|
||||
v3.PropsSet(prop1, 42);
|
||||
v4.PropsSet(prop1, 42);
|
||||
auto prop2 = dba->Property("prop2");
|
||||
auto prop2 = dba.Property("prop2");
|
||||
v1.PropsSet(prop2, 0);
|
||||
v2.PropsSet(prop2, 0);
|
||||
dba->AdvanceCommand();
|
||||
dba.AdvanceCommand();
|
||||
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
@ -641,11 +640,11 @@ TEST(QueryPlan, RemoveProperty) {
|
||||
auto r_p = PROPERTY_LOOKUP("r", prop1);
|
||||
symbol_table[*r_p->expression_] = r_m.edge_sym_;
|
||||
auto set_r_p = std::make_shared<plan::RemoveProperty>(set_n_p, r_p);
|
||||
EXPECT_EQ(2, PullAll(set_r_p, *dba, symbol_table));
|
||||
dba->AdvanceCommand();
|
||||
EXPECT_EQ(2, PullAll(set_r_p, dba, symbol_table));
|
||||
dba.AdvanceCommand();
|
||||
|
||||
EXPECT_EQ(CountIterable(dba->Edges(false)), 2);
|
||||
for (EdgeAccessor edge : dba->Edges(false)) {
|
||||
EXPECT_EQ(CountIterable(dba.Edges(false)), 2);
|
||||
for (EdgeAccessor edge : dba.Edges(false)) {
|
||||
EXPECT_EQ(edge.PropsAt(prop1).type(), PropertyValue::Type::Null);
|
||||
VertexAccessor from = edge.from();
|
||||
VertexAccessor to = edge.to();
|
||||
@ -656,20 +655,20 @@ TEST(QueryPlan, RemoveProperty) {
|
||||
}
|
||||
|
||||
TEST(QueryPlan, RemoveLabels) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
|
||||
auto label1 = dba->Label("label1");
|
||||
auto label2 = dba->Label("label2");
|
||||
auto label3 = dba->Label("label3");
|
||||
auto v1 = dba->InsertVertex();
|
||||
auto label1 = dba.Label("label1");
|
||||
auto label2 = dba.Label("label2");
|
||||
auto label3 = dba.Label("label3");
|
||||
auto v1 = dba.InsertVertex();
|
||||
v1.add_label(label1);
|
||||
v1.add_label(label2);
|
||||
v1.add_label(label3);
|
||||
auto v2 = dba->InsertVertex();
|
||||
auto v2 = dba.InsertVertex();
|
||||
v2.add_label(label1);
|
||||
v2.add_label(label3);
|
||||
dba->AdvanceCommand();
|
||||
dba.AdvanceCommand();
|
||||
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
@ -677,9 +676,9 @@ TEST(QueryPlan, RemoveLabels) {
|
||||
auto n = MakeScanAll(storage, symbol_table, "n");
|
||||
auto label_remove = std::make_shared<plan::RemoveLabels>(
|
||||
n.op_, n.sym_, std::vector<GraphDbTypes::Label>{label1, label2});
|
||||
EXPECT_EQ(2, PullAll(label_remove, *dba, symbol_table));
|
||||
EXPECT_EQ(2, PullAll(label_remove, dba, symbol_table));
|
||||
|
||||
for (VertexAccessor vertex : dba->Vertices(false)) {
|
||||
for (VertexAccessor vertex : dba.Vertices(false)) {
|
||||
vertex.SwitchNew();
|
||||
EXPECT_EQ(1, vertex.labels().size());
|
||||
EXPECT_FALSE(vertex.has_label(label1));
|
||||
@ -688,18 +687,18 @@ TEST(QueryPlan, RemoveLabels) {
|
||||
}
|
||||
|
||||
TEST(QueryPlan, NodeFilterSet) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
// Create a graph such that (v1 {prop: 42}) is connected to v2 and v3.
|
||||
auto v1 = dba->InsertVertex();
|
||||
auto v1 = dba.InsertVertex();
|
||||
auto prop = PROPERTY_PAIR("property");
|
||||
v1.PropsSet(prop.second, 42);
|
||||
auto v2 = dba->InsertVertex();
|
||||
auto v3 = dba->InsertVertex();
|
||||
auto edge_type = dba->EdgeType("Edge");
|
||||
dba->InsertEdge(v1, v2, edge_type);
|
||||
dba->InsertEdge(v1, v3, edge_type);
|
||||
dba->AdvanceCommand();
|
||||
auto v2 = dba.InsertVertex();
|
||||
auto v3 = dba.InsertVertex();
|
||||
auto edge_type = dba.EdgeType("Edge");
|
||||
dba.InsertEdge(v1, v2, edge_type);
|
||||
dba.InsertEdge(v1, v3, edge_type);
|
||||
dba.AdvanceCommand();
|
||||
// Create operations which match (v1 {prop: 42}) -- (v) and increment the
|
||||
// v1.prop. The expected result is two incremenentations, since v1 is matched
|
||||
// twice for 2 edges it has.
|
||||
@ -719,8 +718,8 @@ TEST(QueryPlan, NodeFilterSet) {
|
||||
symbol_table[*set_prop->expression_] = scan_all.sym_;
|
||||
auto add = ADD(set_prop, LITERAL(1));
|
||||
auto set = std::make_shared<plan::SetProperty>(node_filter, set_prop, add);
|
||||
EXPECT_EQ(2, PullAll(set, *dba, symbol_table));
|
||||
dba->AdvanceCommand();
|
||||
EXPECT_EQ(2, PullAll(set, dba, symbol_table));
|
||||
dba.AdvanceCommand();
|
||||
v1.Reconstruct();
|
||||
auto prop_eq = v1.PropsAt(prop.second) == TypedValue(42 + 2);
|
||||
ASSERT_EQ(prop_eq.type(), TypedValue::Type::Bool);
|
||||
@ -728,18 +727,18 @@ TEST(QueryPlan, NodeFilterSet) {
|
||||
}
|
||||
|
||||
TEST(QueryPlan, FilterRemove) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
// Create a graph such that (v1 {prop: 42}) is connected to v2 and v3.
|
||||
auto v1 = dba->InsertVertex();
|
||||
auto v1 = dba.InsertVertex();
|
||||
auto prop = PROPERTY_PAIR("property");
|
||||
v1.PropsSet(prop.second, 42);
|
||||
auto v2 = dba->InsertVertex();
|
||||
auto v3 = dba->InsertVertex();
|
||||
auto edge_type = dba->EdgeType("Edge");
|
||||
dba->InsertEdge(v1, v2, edge_type);
|
||||
dba->InsertEdge(v1, v3, edge_type);
|
||||
dba->AdvanceCommand();
|
||||
auto v2 = dba.InsertVertex();
|
||||
auto v3 = dba.InsertVertex();
|
||||
auto edge_type = dba.EdgeType("Edge");
|
||||
dba.InsertEdge(v1, v2, edge_type);
|
||||
dba.InsertEdge(v1, v3, edge_type);
|
||||
dba.AdvanceCommand();
|
||||
// Create operations which match (v1 {prop: 42}) -- (v) and remove v1.prop.
|
||||
// The expected result is two matches, for each edge of v1.
|
||||
AstTreeStorage storage;
|
||||
@ -757,19 +756,19 @@ TEST(QueryPlan, FilterRemove) {
|
||||
auto rem_prop = PROPERTY_LOOKUP("n", prop);
|
||||
symbol_table[*rem_prop->expression_] = scan_all.sym_;
|
||||
auto rem = std::make_shared<plan::RemoveProperty>(filter, rem_prop);
|
||||
EXPECT_EQ(2, PullAll(rem, *dba, symbol_table));
|
||||
dba->AdvanceCommand();
|
||||
EXPECT_EQ(2, PullAll(rem, dba, symbol_table));
|
||||
dba.AdvanceCommand();
|
||||
v1.Reconstruct();
|
||||
EXPECT_EQ(v1.PropsAt(prop.second).type(), PropertyValue::Type::Null);
|
||||
}
|
||||
|
||||
TEST(QueryPlan, SetRemove) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto v = dba->InsertVertex();
|
||||
auto label1 = dba->Label("label1");
|
||||
auto label2 = dba->Label("label2");
|
||||
dba->AdvanceCommand();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto v = dba.InsertVertex();
|
||||
auto label1 = dba.Label("label1");
|
||||
auto label2 = dba.Label("label2");
|
||||
dba.AdvanceCommand();
|
||||
// Create operations which match (v) and set and remove v :label.
|
||||
// The expected result is single (v) as it was at the start.
|
||||
AstTreeStorage storage;
|
||||
@ -781,8 +780,8 @@ TEST(QueryPlan, SetRemove) {
|
||||
std::vector<GraphDbTypes::Label>{label1, label2});
|
||||
auto rem = std::make_shared<plan::RemoveLabels>(
|
||||
set, scan_all.sym_, std::vector<GraphDbTypes::Label>{label1, label2});
|
||||
EXPECT_EQ(1, PullAll(rem, *dba, symbol_table));
|
||||
dba->AdvanceCommand();
|
||||
EXPECT_EQ(1, PullAll(rem, dba, symbol_table));
|
||||
dba.AdvanceCommand();
|
||||
v.Reconstruct();
|
||||
EXPECT_FALSE(v.has_label(label1));
|
||||
EXPECT_FALSE(v.has_label(label2));
|
||||
@ -795,13 +794,13 @@ TEST(QueryPlan, Merge) {
|
||||
// - merge_match branch looks for an expansion (any direction)
|
||||
// and sets some property (for result validation)
|
||||
// - merge_create branch just sets some other property
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto v1 = dba->InsertVertex();
|
||||
auto v2 = dba->InsertVertex();
|
||||
dba->InsertEdge(v1, v2, dba->EdgeType("Type"));
|
||||
auto v3 = dba->InsertVertex();
|
||||
dba->AdvanceCommand();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto v1 = dba.InsertVertex();
|
||||
auto v2 = dba.InsertVertex();
|
||||
dba.InsertEdge(v1, v2, dba.EdgeType("Type"));
|
||||
auto v3 = dba.InsertVertex();
|
||||
dba.AdvanceCommand();
|
||||
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
@ -823,8 +822,8 @@ TEST(QueryPlan, Merge) {
|
||||
n_p, LITERAL(2));
|
||||
|
||||
auto merge = std::make_shared<plan::Merge>(n.op_, m_set, n_set);
|
||||
ASSERT_EQ(3, PullAll(merge, *dba, symbol_table));
|
||||
dba->AdvanceCommand();
|
||||
ASSERT_EQ(3, PullAll(merge, dba, symbol_table));
|
||||
dba.AdvanceCommand();
|
||||
v1.Reconstruct();
|
||||
v2.Reconstruct();
|
||||
v3.Reconstruct();
|
||||
@ -840,8 +839,8 @@ TEST(QueryPlan, Merge) {
|
||||
TEST(QueryPlan, MergeNoInput) {
|
||||
// merge with no input, creates a single node
|
||||
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
|
||||
@ -851,16 +850,16 @@ TEST(QueryPlan, MergeNoInput) {
|
||||
auto create = std::make_shared<CreateNode>(node, nullptr);
|
||||
auto merge = std::make_shared<plan::Merge>(nullptr, create, create);
|
||||
|
||||
EXPECT_EQ(0, CountIterable(dba->Vertices(false)));
|
||||
EXPECT_EQ(1, PullAll(merge, *dba, symbol_table));
|
||||
dba->AdvanceCommand();
|
||||
EXPECT_EQ(1, CountIterable(dba->Vertices(false)));
|
||||
EXPECT_EQ(0, CountIterable(dba.Vertices(false)));
|
||||
EXPECT_EQ(1, PullAll(merge, dba, symbol_table));
|
||||
dba.AdvanceCommand();
|
||||
EXPECT_EQ(1, CountIterable(dba.Vertices(false)));
|
||||
}
|
||||
|
||||
TEST(QueryPlan, SetPropertyOnNull) {
|
||||
// SET (Null).prop = 42
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
auto prop = PROPERTY_PAIR("property");
|
||||
@ -869,13 +868,13 @@ TEST(QueryPlan, SetPropertyOnNull) {
|
||||
auto n_prop = storage.Create<PropertyLookup>(null, prop);
|
||||
auto once = std::make_shared<Once>();
|
||||
auto set_op = std::make_shared<plan::SetProperty>(once, n_prop, literal);
|
||||
EXPECT_EQ(1, PullAll(set_op, *dba, symbol_table));
|
||||
EXPECT_EQ(1, PullAll(set_op, dba, symbol_table));
|
||||
}
|
||||
|
||||
TEST(QueryPlan, SetPropertiesOnNull) {
|
||||
// OPTIONAL MATCH (n) SET n = n
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
auto n = MakeScanAll(storage, symbol_table, "n");
|
||||
@ -885,15 +884,15 @@ TEST(QueryPlan, SetPropertiesOnNull) {
|
||||
std::vector<Symbol>{n.sym_});
|
||||
auto set_op = std::make_shared<plan::SetProperties>(
|
||||
optional, n.sym_, n_ident, plan::SetProperties::Op::REPLACE);
|
||||
EXPECT_EQ(0, CountIterable(dba->Vertices(false)));
|
||||
EXPECT_EQ(1, PullAll(set_op, *dba, symbol_table));
|
||||
EXPECT_EQ(0, CountIterable(dba.Vertices(false)));
|
||||
EXPECT_EQ(1, PullAll(set_op, dba, symbol_table));
|
||||
}
|
||||
|
||||
TEST(QueryPlan, SetLabelsOnNull) {
|
||||
// OPTIONAL MATCH (n) SET n :label
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto label = dba->Label("label");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto label = dba.Label("label");
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
auto n = MakeScanAll(storage, symbol_table, "n");
|
||||
@ -903,14 +902,14 @@ TEST(QueryPlan, SetLabelsOnNull) {
|
||||
std::vector<Symbol>{n.sym_});
|
||||
auto set_op = std::make_shared<plan::SetLabels>(
|
||||
optional, n.sym_, std::vector<GraphDbTypes::Label>{label});
|
||||
EXPECT_EQ(0, CountIterable(dba->Vertices(false)));
|
||||
EXPECT_EQ(1, PullAll(set_op, *dba, symbol_table));
|
||||
EXPECT_EQ(0, CountIterable(dba.Vertices(false)));
|
||||
EXPECT_EQ(1, PullAll(set_op, dba, symbol_table));
|
||||
}
|
||||
|
||||
TEST(QueryPlan, RemovePropertyOnNull) {
|
||||
// REMOVE (Null).prop
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
auto prop = PROPERTY_PAIR("property");
|
||||
@ -918,14 +917,14 @@ TEST(QueryPlan, RemovePropertyOnNull) {
|
||||
auto n_prop = storage.Create<PropertyLookup>(null, prop);
|
||||
auto once = std::make_shared<Once>();
|
||||
auto remove_op = std::make_shared<plan::RemoveProperty>(once, n_prop);
|
||||
EXPECT_EQ(1, PullAll(remove_op, *dba, symbol_table));
|
||||
EXPECT_EQ(1, PullAll(remove_op, dba, symbol_table));
|
||||
}
|
||||
|
||||
TEST(QueryPlan, RemoveLabelsOnNull) {
|
||||
// OPTIONAL MATCH (n) REMOVE n :label
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto label = dba->Label("label");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto label = dba.Label("label");
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
auto n = MakeScanAll(storage, symbol_table, "n");
|
||||
@ -935,19 +934,19 @@ TEST(QueryPlan, RemoveLabelsOnNull) {
|
||||
std::vector<Symbol>{n.sym_});
|
||||
auto remove_op = std::make_shared<plan::RemoveLabels>(
|
||||
optional, n.sym_, std::vector<GraphDbTypes::Label>{label});
|
||||
EXPECT_EQ(0, CountIterable(dba->Vertices(false)));
|
||||
EXPECT_EQ(1, PullAll(remove_op, *dba, symbol_table));
|
||||
EXPECT_EQ(0, CountIterable(dba.Vertices(false)));
|
||||
EXPECT_EQ(1, PullAll(remove_op, dba, symbol_table));
|
||||
}
|
||||
|
||||
TEST(QueryPlan, CreateIndex) {
|
||||
// CREATE INDEX ON :Label(property)
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto label = dba->Label("label");
|
||||
auto property = dba->Property("property");
|
||||
EXPECT_FALSE(dba->LabelPropertyIndexExists(label, property));
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto label = dba.Label("label");
|
||||
auto property = dba.Property("property");
|
||||
EXPECT_FALSE(dba.LabelPropertyIndexExists(label, property));
|
||||
auto create_index = std::make_shared<plan::CreateIndex>(label, property);
|
||||
SymbolTable symbol_table;
|
||||
EXPECT_EQ(PullAll(create_index, *dba, symbol_table), 1);
|
||||
EXPECT_TRUE(dba->LabelPropertyIndexExists(label, property));
|
||||
EXPECT_EQ(PullAll(create_index, dba, symbol_table), 1);
|
||||
EXPECT_TRUE(dba.LabelPropertyIndexExists(label, property));
|
||||
}
|
||||
|
@ -2,31 +2,41 @@
|
||||
// that's not easily testable with single-phase testing. instead, for
|
||||
// easy testing and latter readability they are tested end-to-end.
|
||||
|
||||
#include <experimental/optional>
|
||||
|
||||
#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();
|
||||
std::experimental::optional<GraphDb> db_;
|
||||
std::experimental::optional<GraphDbAccessor> dba_;
|
||||
|
||||
/** Commits the current transaction and refreshes the db_
|
||||
void SetUp() {
|
||||
db_.emplace();
|
||||
dba_.emplace(*db_);
|
||||
}
|
||||
|
||||
void TearDown() {
|
||||
dba_ = std::experimental::nullopt;
|
||||
db_ = std::experimental::nullopt;
|
||||
}
|
||||
|
||||
/** Commits the current transaction and refreshes the dba_
|
||||
* variable to hold a new accessor with a new transaction */
|
||||
void Commit() {
|
||||
db_->Commit();
|
||||
auto next_db = dbms_.active();
|
||||
db_.swap(next_db);
|
||||
dba_->Commit();
|
||||
dba_.emplace(*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, {}, false);
|
||||
query::Interpreter().Interpret(query, *dba_, results, {}, false);
|
||||
return results.GetResults();
|
||||
}
|
||||
};
|
||||
|
@ -15,7 +15,7 @@
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "communication/result_stream_faker.hpp"
|
||||
#include "database/dbms.hpp"
|
||||
#include "database/graph_db.hpp"
|
||||
#include "query/context.hpp"
|
||||
#include "query/exceptions.hpp"
|
||||
#include "query/plan/operator.hpp"
|
||||
@ -27,19 +27,19 @@ using namespace query::plan;
|
||||
|
||||
class MatchReturnFixture : public testing::Test {
|
||||
protected:
|
||||
Dbms dbms;
|
||||
std::unique_ptr<GraphDbAccessor> dba = dbms.active();
|
||||
GraphDb db_;
|
||||
GraphDbAccessor dba_{db_};
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
|
||||
void AddVertices(int count) {
|
||||
for (int i = 0; i < count; i++) dba->InsertVertex();
|
||||
for (int i = 0; i < count; i++) dba_.InsertVertex();
|
||||
}
|
||||
|
||||
template <typename TResult>
|
||||
std::vector<TResult> Results(std::shared_ptr<Produce> &op) {
|
||||
std::vector<TResult> res;
|
||||
for (const auto &row : CollectProduce(op.get(), symbol_table, *dba))
|
||||
for (const auto &row : CollectProduce(op.get(), symbol_table, dba_))
|
||||
res.emplace_back(row[0].Value<TResult>());
|
||||
return res;
|
||||
}
|
||||
@ -47,7 +47,7 @@ class MatchReturnFixture : public testing::Test {
|
||||
|
||||
TEST_F(MatchReturnFixture, MatchReturn) {
|
||||
AddVertices(2);
|
||||
dba->AdvanceCommand();
|
||||
dba_.AdvanceCommand();
|
||||
|
||||
auto test_pull_count = [&](GraphView graph_view) {
|
||||
auto scan_all =
|
||||
@ -57,21 +57,21 @@ TEST_F(MatchReturnFixture, MatchReturn) {
|
||||
symbol_table[*output->expression_] = scan_all.sym_;
|
||||
symbol_table[*output] =
|
||||
symbol_table.CreateSymbol("named_expression_1", true);
|
||||
return PullAll(produce, *dba, symbol_table);
|
||||
return PullAll(produce, dba_, symbol_table);
|
||||
};
|
||||
|
||||
EXPECT_EQ(2, test_pull_count(GraphView::NEW));
|
||||
EXPECT_EQ(2, test_pull_count(GraphView::OLD));
|
||||
dba->InsertVertex();
|
||||
dba_.InsertVertex();
|
||||
EXPECT_EQ(3, test_pull_count(GraphView::NEW));
|
||||
EXPECT_EQ(2, test_pull_count(GraphView::OLD));
|
||||
dba->AdvanceCommand();
|
||||
dba_.AdvanceCommand();
|
||||
EXPECT_EQ(3, test_pull_count(GraphView::OLD));
|
||||
}
|
||||
|
||||
TEST_F(MatchReturnFixture, MatchReturnPath) {
|
||||
AddVertices(2);
|
||||
dba->AdvanceCommand();
|
||||
dba_.AdvanceCommand();
|
||||
|
||||
auto scan_all = MakeScanAll(storage, symbol_table, "n", nullptr);
|
||||
Symbol path_sym = symbol_table.CreateSymbol("path", true);
|
||||
@ -84,19 +84,19 @@ TEST_F(MatchReturnFixture, MatchReturnPath) {
|
||||
auto results = Results<query::Path>(produce);
|
||||
ASSERT_EQ(results.size(), 2);
|
||||
std::vector<query::Path> expected_paths;
|
||||
for (const auto &v : dba->Vertices(false)) expected_paths.emplace_back(v);
|
||||
for (const auto &v : dba_.Vertices(false)) expected_paths.emplace_back(v);
|
||||
ASSERT_EQ(expected_paths.size(), 2);
|
||||
EXPECT_TRUE(std::is_permutation(expected_paths.begin(), expected_paths.end(),
|
||||
results.begin()));
|
||||
}
|
||||
|
||||
TEST(QueryPlan, MatchReturnCartesian) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
|
||||
dba->InsertVertex().add_label(dba->Label("l1"));
|
||||
dba->InsertVertex().add_label(dba->Label("l2"));
|
||||
dba->AdvanceCommand();
|
||||
dba.InsertVertex().add_label(dba.Label("l1"));
|
||||
dba.InsertVertex().add_label(dba.Label("l2"));
|
||||
dba.AdvanceCommand();
|
||||
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
@ -113,7 +113,7 @@ TEST(QueryPlan, MatchReturnCartesian) {
|
||||
symbol_table.CreateSymbol("named_expression_2", true);
|
||||
auto produce = MakeProduce(m.op_, return_n, return_m);
|
||||
|
||||
auto results = CollectProduce(produce.get(), symbol_table, *dba);
|
||||
auto results = CollectProduce(produce.get(), symbol_table, dba);
|
||||
EXPECT_EQ(results.size(), 4);
|
||||
// ensure the result ordering is OK:
|
||||
// "n" from the results is the same for the first two rows, while "m" isn't
|
||||
@ -124,13 +124,13 @@ TEST(QueryPlan, MatchReturnCartesian) {
|
||||
}
|
||||
|
||||
TEST(QueryPlan, StandaloneReturn) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
|
||||
// add a few nodes to the database
|
||||
dba->InsertVertex();
|
||||
dba->InsertVertex();
|
||||
dba->AdvanceCommand();
|
||||
dba.InsertVertex();
|
||||
dba.InsertVertex();
|
||||
dba.AdvanceCommand();
|
||||
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
@ -139,25 +139,25 @@ TEST(QueryPlan, StandaloneReturn) {
|
||||
auto produce = MakeProduce(std::shared_ptr<LogicalOperator>(nullptr), output);
|
||||
symbol_table[*output] = symbol_table.CreateSymbol("named_expression_1", true);
|
||||
|
||||
auto results = CollectProduce(produce.get(), symbol_table, *dba);
|
||||
auto results = CollectProduce(produce.get(), symbol_table, dba);
|
||||
EXPECT_EQ(results.size(), 1);
|
||||
EXPECT_EQ(results[0].size(), 1);
|
||||
EXPECT_EQ(results[0][0].Value<int64_t>(), 42);
|
||||
}
|
||||
|
||||
TEST(QueryPlan, NodeFilterLabelsAndProperties) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
|
||||
// add a few nodes to the database
|
||||
GraphDbTypes::Label label = dba->Label("Label");
|
||||
GraphDbTypes::Label label = dba.Label("Label");
|
||||
auto property = PROPERTY_PAIR("Property");
|
||||
auto v1 = dba->InsertVertex();
|
||||
auto v2 = dba->InsertVertex();
|
||||
auto v3 = dba->InsertVertex();
|
||||
auto v4 = dba->InsertVertex();
|
||||
auto v5 = dba->InsertVertex();
|
||||
dba->InsertVertex();
|
||||
auto v1 = dba.InsertVertex();
|
||||
auto v2 = dba.InsertVertex();
|
||||
auto v3 = dba.InsertVertex();
|
||||
auto v4 = dba.InsertVertex();
|
||||
auto v5 = dba.InsertVertex();
|
||||
dba.InsertVertex();
|
||||
// test all combination of (label | no_label) * (no_prop | wrong_prop |
|
||||
// right_prop)
|
||||
// only v1-v3 will have the right labels
|
||||
@ -169,7 +169,7 @@ TEST(QueryPlan, NodeFilterLabelsAndProperties) {
|
||||
v2.PropsSet(property.second, 1);
|
||||
v4.PropsSet(property.second, 42);
|
||||
v5.PropsSet(property.second, 1);
|
||||
dba->AdvanceCommand();
|
||||
dba.AdvanceCommand();
|
||||
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
@ -191,40 +191,40 @@ TEST(QueryPlan, NodeFilterLabelsAndProperties) {
|
||||
symbol_table[*output] = symbol_table.CreateSymbol("named_expression_1", true);
|
||||
auto produce = MakeProduce(node_filter, output);
|
||||
|
||||
EXPECT_EQ(1, PullAll(produce, *dba, symbol_table));
|
||||
EXPECT_EQ(1, PullAll(produce, dba, symbol_table));
|
||||
|
||||
// test that filtering works with old records
|
||||
v4.Reconstruct();
|
||||
v4.add_label(label);
|
||||
EXPECT_EQ(1, PullAll(produce, *dba, symbol_table));
|
||||
dba->AdvanceCommand();
|
||||
EXPECT_EQ(2, PullAll(produce, *dba, symbol_table));
|
||||
EXPECT_EQ(1, PullAll(produce, dba, symbol_table));
|
||||
dba.AdvanceCommand();
|
||||
EXPECT_EQ(2, PullAll(produce, dba, symbol_table));
|
||||
}
|
||||
|
||||
TEST(QueryPlan, NodeFilterMultipleLabels) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
|
||||
// add a few nodes to the database
|
||||
GraphDbTypes::Label label1 = dba->Label("label1");
|
||||
GraphDbTypes::Label label2 = dba->Label("label2");
|
||||
GraphDbTypes::Label label3 = dba->Label("label3");
|
||||
GraphDbTypes::Label label1 = dba.Label("label1");
|
||||
GraphDbTypes::Label label2 = dba.Label("label2");
|
||||
GraphDbTypes::Label label3 = dba.Label("label3");
|
||||
// the test will look for nodes that have label1 and label2
|
||||
dba->InsertVertex(); // NOT accepted
|
||||
dba->InsertVertex().add_label(label1); // NOT accepted
|
||||
dba->InsertVertex().add_label(label2); // NOT accepted
|
||||
dba->InsertVertex().add_label(label3); // NOT accepted
|
||||
auto v1 = dba->InsertVertex(); // YES accepted
|
||||
dba.InsertVertex(); // NOT accepted
|
||||
dba.InsertVertex().add_label(label1); // NOT accepted
|
||||
dba.InsertVertex().add_label(label2); // NOT accepted
|
||||
dba.InsertVertex().add_label(label3); // NOT accepted
|
||||
auto v1 = dba.InsertVertex(); // YES accepted
|
||||
v1.add_label(label1);
|
||||
v1.add_label(label2);
|
||||
auto v2 = dba->InsertVertex(); // NOT accepted
|
||||
auto v2 = dba.InsertVertex(); // NOT accepted
|
||||
v2.add_label(label1);
|
||||
v2.add_label(label3);
|
||||
auto v3 = dba->InsertVertex(); // YES accepted
|
||||
auto v3 = dba.InsertVertex(); // YES accepted
|
||||
v3.add_label(label1);
|
||||
v3.add_label(label2);
|
||||
v3.add_label(label3);
|
||||
dba->AdvanceCommand();
|
||||
dba.AdvanceCommand();
|
||||
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
@ -247,30 +247,30 @@ TEST(QueryPlan, NodeFilterMultipleLabels) {
|
||||
symbol_table[*output] = symbol_table.CreateSymbol("named_expression_1", true);
|
||||
symbol_table[*output->expression_] = n.sym_;
|
||||
|
||||
auto results = CollectProduce(produce.get(), symbol_table, *dba);
|
||||
auto results = CollectProduce(produce.get(), symbol_table, dba);
|
||||
EXPECT_EQ(results.size(), 2);
|
||||
}
|
||||
|
||||
class ExpandFixture : public testing::Test {
|
||||
protected:
|
||||
Dbms dbms;
|
||||
std::unique_ptr<GraphDbAccessor> dba = dbms.active();
|
||||
GraphDb db_;
|
||||
GraphDbAccessor dba_{db_};
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
|
||||
// make a V-graph (v3)<-[r2]-(v1)-[r1]->(v2)
|
||||
VertexAccessor v1 = dba->InsertVertex();
|
||||
VertexAccessor v2 = dba->InsertVertex();
|
||||
VertexAccessor v3 = dba->InsertVertex();
|
||||
GraphDbTypes::EdgeType edge_type = dba->EdgeType("Edge");
|
||||
EdgeAccessor r1 = dba->InsertEdge(v1, v2, edge_type);
|
||||
EdgeAccessor r2 = dba->InsertEdge(v1, v3, edge_type);
|
||||
VertexAccessor v1 = dba_.InsertVertex();
|
||||
VertexAccessor v2 = dba_.InsertVertex();
|
||||
VertexAccessor v3 = dba_.InsertVertex();
|
||||
GraphDbTypes::EdgeType edge_type = dba_.EdgeType("Edge");
|
||||
EdgeAccessor r1 = dba_.InsertEdge(v1, v2, edge_type);
|
||||
EdgeAccessor r2 = dba_.InsertEdge(v1, v3, edge_type);
|
||||
|
||||
void SetUp() override {
|
||||
v1.add_label((GraphDbTypes::Label)1);
|
||||
v2.add_label((GraphDbTypes::Label)2);
|
||||
v3.add_label((GraphDbTypes::Label)3);
|
||||
dba->AdvanceCommand();
|
||||
dba_.AdvanceCommand();
|
||||
}
|
||||
};
|
||||
|
||||
@ -287,7 +287,7 @@ TEST_F(ExpandFixture, Expand) {
|
||||
symbol_table.CreateSymbol("named_expression_1", true);
|
||||
auto produce = MakeProduce(r_m.op_, output);
|
||||
|
||||
return PullAll(produce, *dba, symbol_table);
|
||||
return PullAll(produce, dba_, symbol_table);
|
||||
};
|
||||
|
||||
EXPECT_EQ(2, test_expand(EdgeAtom::Direction::OUT, GraphView::AS_IS));
|
||||
@ -298,15 +298,15 @@ TEST_F(ExpandFixture, Expand) {
|
||||
v1.Reconstruct();
|
||||
v2.Reconstruct();
|
||||
v3.Reconstruct();
|
||||
dba->InsertEdge(v1, v2, edge_type);
|
||||
dba->InsertEdge(v1, v3, edge_type);
|
||||
dba_.InsertEdge(v1, v2, edge_type);
|
||||
dba_.InsertEdge(v1, v3, edge_type);
|
||||
EXPECT_EQ(2, test_expand(EdgeAtom::Direction::OUT, GraphView::OLD));
|
||||
EXPECT_EQ(2, test_expand(EdgeAtom::Direction::IN, GraphView::OLD));
|
||||
EXPECT_EQ(4, test_expand(EdgeAtom::Direction::BOTH, GraphView::OLD));
|
||||
EXPECT_EQ(4, test_expand(EdgeAtom::Direction::OUT, GraphView::NEW));
|
||||
EXPECT_EQ(4, test_expand(EdgeAtom::Direction::IN, GraphView::NEW));
|
||||
EXPECT_EQ(8, test_expand(EdgeAtom::Direction::BOTH, GraphView::NEW));
|
||||
dba->AdvanceCommand();
|
||||
dba_.AdvanceCommand();
|
||||
EXPECT_EQ(4, test_expand(EdgeAtom::Direction::OUT, GraphView::OLD));
|
||||
EXPECT_EQ(4, test_expand(EdgeAtom::Direction::IN, GraphView::OLD));
|
||||
EXPECT_EQ(8, test_expand(EdgeAtom::Direction::BOTH, GraphView::OLD));
|
||||
@ -326,7 +326,7 @@ TEST_F(ExpandFixture, ExpandPath) {
|
||||
auto produce = MakeProduce(path, output);
|
||||
|
||||
std::vector<query::Path> expected_paths{{v1, r2, v3}, {v1, r1, v2}};
|
||||
auto results = CollectProduce(produce.get(), symbol_table, *dba);
|
||||
auto results = CollectProduce(produce.get(), symbol_table, dba_);
|
||||
ASSERT_EQ(results.size(), 2);
|
||||
std::vector<query::Path> results_paths;
|
||||
for (const auto &result : results)
|
||||
@ -353,12 +353,12 @@ class QueryPlanExpandVariable : public testing::Test {
|
||||
// a lot below in test declaration
|
||||
using map_int = std::unordered_map<int, int>;
|
||||
|
||||
Dbms dbms;
|
||||
std::unique_ptr<GraphDbAccessor> dba = dbms.active();
|
||||
GraphDb db_;
|
||||
GraphDbAccessor dba_{db_};
|
||||
// labels for layers in the double chain
|
||||
std::vector<GraphDbTypes::Label> labels;
|
||||
// for all the edges
|
||||
GraphDbTypes::EdgeType edge_type = dba->EdgeType("edge_type");
|
||||
GraphDbTypes::EdgeType edge_type = dba_.EdgeType("edge_type");
|
||||
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
@ -372,26 +372,26 @@ class QueryPlanExpandVariable : public testing::Test {
|
||||
std::vector<VertexAccessor> layer;
|
||||
for (int from_layer_ind = -1; from_layer_ind < chain_length - 1;
|
||||
from_layer_ind++) {
|
||||
std::vector<VertexAccessor> new_layer{dba->InsertVertex(),
|
||||
dba->InsertVertex()};
|
||||
auto label = dba->Label(std::to_string(from_layer_ind + 1));
|
||||
std::vector<VertexAccessor> new_layer{dba_.InsertVertex(),
|
||||
dba_.InsertVertex()};
|
||||
auto label = dba_.Label(std::to_string(from_layer_ind + 1));
|
||||
labels.push_back(label);
|
||||
for (size_t v_to_ind = 0; v_to_ind < new_layer.size(); v_to_ind++) {
|
||||
auto &v_to = new_layer[v_to_ind];
|
||||
v_to.add_label(label);
|
||||
for (size_t v_from_ind = 0; v_from_ind < layer.size(); v_from_ind++) {
|
||||
auto &v_from = layer[v_from_ind];
|
||||
auto edge = dba->InsertEdge(v_from, v_to, edge_type);
|
||||
edge.PropsSet(dba->Property("p"),
|
||||
auto edge = dba_.InsertEdge(v_from, v_to, edge_type);
|
||||
edge.PropsSet(dba_.Property("p"),
|
||||
fmt::format("V{}{}->V{}{}", from_layer_ind, v_from_ind,
|
||||
from_layer_ind + 1, v_to_ind));
|
||||
}
|
||||
}
|
||||
layer = new_layer;
|
||||
}
|
||||
dba->AdvanceCommand();
|
||||
ASSERT_EQ(CountIterable(dba->Vertices(false)), 2 * chain_length);
|
||||
ASSERT_EQ(CountIterable(dba->Edges(false)), 4 * (chain_length - 1));
|
||||
dba_.AdvanceCommand();
|
||||
ASSERT_EQ(CountIterable(dba_.Vertices(false)), 2 * chain_length);
|
||||
ASSERT_EQ(CountIterable(dba_.Edges(false)), 4 * (chain_length - 1));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -457,8 +457,8 @@ class QueryPlanExpandVariable : public testing::Test {
|
||||
template <typename TResult>
|
||||
auto GetResults(std::shared_ptr<LogicalOperator> input_op, Symbol symbol) {
|
||||
Frame frame(symbol_table.max_position());
|
||||
auto cursor = input_op->MakeCursor(*dba);
|
||||
Context context(*dba);
|
||||
auto cursor = input_op->MakeCursor(dba_);
|
||||
Context context(dba_);
|
||||
context.symbol_table_ = symbol_table;
|
||||
std::vector<TResult> results;
|
||||
while (cursor->Pull(frame, context))
|
||||
@ -619,32 +619,32 @@ TEST_F(QueryPlanExpandVariable, EdgeUniquenessTwoVariableExpansions) {
|
||||
}
|
||||
|
||||
TEST_F(QueryPlanExpandVariable, GraphState) {
|
||||
auto test_expand = [&](
|
||||
GraphView graph_view,
|
||||
const std::vector<GraphDbTypes::EdgeType> &edge_types) {
|
||||
auto e = Edge("r", EdgeAtom::Direction::OUT);
|
||||
return GetEdgeListSizes(
|
||||
AddMatch<ExpandVariable>(nullptr, "n", 0, EdgeAtom::Direction::OUT,
|
||||
edge_types, 2, 2, e, "m", graph_view),
|
||||
e);
|
||||
};
|
||||
auto test_expand =
|
||||
[&](GraphView graph_view,
|
||||
const std::vector<GraphDbTypes::EdgeType> &edge_types) {
|
||||
auto e = Edge("r", EdgeAtom::Direction::OUT);
|
||||
return GetEdgeListSizes(
|
||||
AddMatch<ExpandVariable>(nullptr, "n", 0, EdgeAtom::Direction::OUT,
|
||||
edge_types, 2, 2, e, "m", graph_view),
|
||||
e);
|
||||
};
|
||||
|
||||
auto new_edge_type = dba->EdgeType("some_type");
|
||||
auto new_edge_type = dba_.EdgeType("some_type");
|
||||
// add two vertices branching out from the second layer
|
||||
for (VertexAccessor &vertex : dba->Vertices(true))
|
||||
for (VertexAccessor &vertex : dba_.Vertices(true))
|
||||
if (vertex.has_label(labels[1])) {
|
||||
auto new_vertex = dba->InsertVertex();
|
||||
dba->InsertEdge(vertex, new_vertex, new_edge_type);
|
||||
auto new_vertex = dba_.InsertVertex();
|
||||
dba_.InsertEdge(vertex, new_vertex, new_edge_type);
|
||||
}
|
||||
ASSERT_EQ(CountIterable(dba->Vertices(false)), 6);
|
||||
ASSERT_EQ(CountIterable(dba->Vertices(true)), 8);
|
||||
ASSERT_EQ(CountIterable(dba_.Vertices(false)), 6);
|
||||
ASSERT_EQ(CountIterable(dba_.Vertices(true)), 8);
|
||||
|
||||
EXPECT_EQ(test_expand(GraphView::OLD, {}), (map_int{{2, 8}}));
|
||||
EXPECT_EQ(test_expand(GraphView::OLD, {new_edge_type}), (map_int{}));
|
||||
EXPECT_EQ(test_expand(GraphView::NEW, {}), (map_int{{2, 12}}));
|
||||
EXPECT_EQ(test_expand(GraphView::NEW, {edge_type}), (map_int{{2, 8}}));
|
||||
EXPECT_EQ(test_expand(GraphView::NEW, {new_edge_type}), (map_int{}));
|
||||
dba->AdvanceCommand();
|
||||
dba_.AdvanceCommand();
|
||||
for (const auto graph_view : {GraphView::OLD, GraphView::NEW}) {
|
||||
EXPECT_EQ(test_expand(graph_view, {}), (map_int{{2, 12}}));
|
||||
EXPECT_EQ(test_expand(graph_view, {edge_type}), (map_int{{2, 8}}));
|
||||
@ -669,7 +669,7 @@ TEST_F(QueryPlanExpandVariable, NamedPath) {
|
||||
std::vector<Symbol>{find_symbol("n"), e, find_symbol("m")});
|
||||
|
||||
std::vector<query::Path> expected_paths;
|
||||
for (const auto &v : dba->Vertices(labels[0], false))
|
||||
for (const auto &v : dba_.Vertices(labels[0], false))
|
||||
for (const auto &e1 : v.out())
|
||||
for (const auto &e2 : e1.to().out())
|
||||
expected_paths.emplace_back(v, e1, e1.to(), e2, e2.to());
|
||||
@ -689,20 +689,20 @@ struct hash<std::pair<int, int>> {
|
||||
return p.first + 31 * p.second;
|
||||
}
|
||||
};
|
||||
}
|
||||
} // namespace std
|
||||
|
||||
// TODO test optional + variable length
|
||||
|
||||
/** A test fixture for breadth first expansion */
|
||||
class QueryPlanExpandBreadthFirst : public testing::Test {
|
||||
protected:
|
||||
Dbms dbms_;
|
||||
// style-guide non-conformant name due to PROPERTY_PAIR and PROPERTY_LOOKUP
|
||||
// macro requirements
|
||||
std::unique_ptr<GraphDbAccessor> dba = dbms_.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba{db};
|
||||
std::pair<std::string, GraphDbTypes::Property> prop =
|
||||
PROPERTY_PAIR("property");
|
||||
GraphDbTypes::EdgeType edge_type = dba->EdgeType("edge_type");
|
||||
GraphDbTypes::EdgeType edge_type = dba.EdgeType("edge_type");
|
||||
|
||||
// make 4 vertices because we'll need to compare against them exactly
|
||||
// v[0] has `prop` with the value 0
|
||||
@ -721,12 +721,12 @@ class QueryPlanExpandBreadthFirst : public testing::Test {
|
||||
|
||||
void SetUp() {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
v.push_back(dba->InsertVertex());
|
||||
v.push_back(dba.InsertVertex());
|
||||
v.back().PropsSet(prop.second, i);
|
||||
}
|
||||
|
||||
auto add_edge = [&](int from, int to) {
|
||||
EdgeAccessor edge = dba->InsertEdge(v[from], v[to], edge_type);
|
||||
EdgeAccessor edge = dba.InsertEdge(v[from], v[to], edge_type);
|
||||
edge.PropsSet(prop.second, from * 10 + to);
|
||||
e.emplace(std::make_pair(from, to), edge);
|
||||
};
|
||||
@ -738,7 +738,7 @@ class QueryPlanExpandBreadthFirst : public testing::Test {
|
||||
add_edge(3, 2);
|
||||
add_edge(2, 2);
|
||||
|
||||
dba->AdvanceCommand();
|
||||
dba.AdvanceCommand();
|
||||
for (auto &vertex : v) vertex.Reconstruct();
|
||||
for (auto &edge : e) edge.second.Reconstruct();
|
||||
}
|
||||
@ -772,9 +772,9 @@ class QueryPlanExpandBreadthFirst : public testing::Test {
|
||||
inner_edge, inner_node, where, graph_view);
|
||||
|
||||
Frame frame(symbol_table.max_position());
|
||||
auto cursor = last_op->MakeCursor(*dba);
|
||||
auto cursor = last_op->MakeCursor(dba);
|
||||
std::vector<std::pair<std::vector<EdgeAccessor>, VertexAccessor>> results;
|
||||
Context context(*dba);
|
||||
Context context(dba);
|
||||
context.symbol_table_ = symbol_table;
|
||||
while (cursor->Pull(frame, context)) {
|
||||
results.emplace_back(std::vector<EdgeAccessor>(),
|
||||
@ -867,14 +867,14 @@ TEST_F(QueryPlanExpandBreadthFirst, GraphState) {
|
||||
};
|
||||
EXPECT_EQ(ExpandSize(GraphView::OLD), 3);
|
||||
EXPECT_EQ(ExpandSize(GraphView::NEW), 3);
|
||||
auto new_vertex = dba->InsertVertex();
|
||||
auto new_vertex = dba.InsertVertex();
|
||||
new_vertex.PropsSet(prop.second, 4);
|
||||
dba->InsertEdge(v[3], new_vertex, edge_type);
|
||||
EXPECT_EQ(CountIterable(dba->Vertices(false)), 4);
|
||||
EXPECT_EQ(CountIterable(dba->Vertices(true)), 5);
|
||||
dba.InsertEdge(v[3], new_vertex, edge_type);
|
||||
EXPECT_EQ(CountIterable(dba.Vertices(false)), 4);
|
||||
EXPECT_EQ(CountIterable(dba.Vertices(true)), 5);
|
||||
EXPECT_EQ(ExpandSize(GraphView::OLD), 3);
|
||||
EXPECT_EQ(ExpandSize(GraphView::NEW), 4);
|
||||
dba->AdvanceCommand();
|
||||
dba.AdvanceCommand();
|
||||
EXPECT_EQ(ExpandSize(GraphView::OLD), 4);
|
||||
EXPECT_EQ(ExpandSize(GraphView::NEW), 4);
|
||||
}
|
||||
@ -916,24 +916,24 @@ TEST_F(QueryPlanExpandBreadthFirst, ExistingNode) {
|
||||
}
|
||||
|
||||
TEST(QueryPlan, ExpandOptional) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
|
||||
// graph (v2 {p: 2})<-[:T]-(v1 {p: 1})-[:T]->(v3 {p: 2})
|
||||
auto prop = dba->Property("p");
|
||||
auto edge_type = dba->EdgeType("T");
|
||||
auto v1 = dba->InsertVertex();
|
||||
auto prop = dba.Property("p");
|
||||
auto edge_type = dba.EdgeType("T");
|
||||
auto v1 = dba.InsertVertex();
|
||||
v1.PropsSet(prop, 1);
|
||||
auto v2 = dba->InsertVertex();
|
||||
auto v2 = dba.InsertVertex();
|
||||
v2.PropsSet(prop, 2);
|
||||
dba->InsertEdge(v1, v2, edge_type);
|
||||
auto v3 = dba->InsertVertex();
|
||||
dba.InsertEdge(v1, v2, edge_type);
|
||||
auto v3 = dba.InsertVertex();
|
||||
v3.PropsSet(prop, 2);
|
||||
dba->InsertEdge(v1, v3, edge_type);
|
||||
dba->AdvanceCommand();
|
||||
dba.InsertEdge(v1, v3, edge_type);
|
||||
dba.AdvanceCommand();
|
||||
|
||||
// MATCH (n) OPTIONAL MATCH (n)-[r]->(m)
|
||||
auto n = MakeScanAll(storage, symbol_table, "n");
|
||||
@ -954,7 +954,7 @@ TEST(QueryPlan, ExpandOptional) {
|
||||
symbol_table[*m_ne] = symbol_table.CreateSymbol("m", true);
|
||||
auto produce = MakeProduce(optional, n_ne, r_ne, m_ne);
|
||||
|
||||
auto results = CollectProduce(produce.get(), symbol_table, *dba);
|
||||
auto results = CollectProduce(produce.get(), symbol_table, dba);
|
||||
ASSERT_EQ(4, results.size());
|
||||
int v1_is_n_count = 0;
|
||||
for (auto &row : results) {
|
||||
@ -975,8 +975,8 @@ TEST(QueryPlan, ExpandOptional) {
|
||||
}
|
||||
|
||||
TEST(QueryPlan, OptionalMatchEmptyDB) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
@ -991,14 +991,14 @@ TEST(QueryPlan, OptionalMatchEmptyDB) {
|
||||
std::vector<Symbol>{n.sym_});
|
||||
auto produce = MakeProduce(optional, n_ne);
|
||||
|
||||
auto results = CollectProduce(produce.get(), symbol_table, *dba);
|
||||
auto results = CollectProduce(produce.get(), symbol_table, dba);
|
||||
ASSERT_EQ(1, results.size());
|
||||
EXPECT_EQ(results[0][0].type(), TypedValue::Type::Null);
|
||||
}
|
||||
|
||||
TEST(QueryPlan, OptionalMatchEmptyDBExpandFromNode) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
// OPTIONAL MATCH (n)
|
||||
@ -1019,26 +1019,26 @@ TEST(QueryPlan, OptionalMatchEmptyDBExpandFromNode) {
|
||||
symbol_table[*m_ne->expression_] = r_m.node_sym_;
|
||||
symbol_table[*m_ne] = symbol_table.CreateSymbol("m", true);
|
||||
auto produce = MakeProduce(r_m.op_, m_ne);
|
||||
auto results = CollectProduce(produce.get(), symbol_table, *dba);
|
||||
auto results = CollectProduce(produce.get(), symbol_table, dba);
|
||||
EXPECT_EQ(0, results.size());
|
||||
}
|
||||
|
||||
TEST(QueryPlan, OptionalMatchThenExpandToMissingNode) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
// Make a graph with 2 connected, unlabeled nodes.
|
||||
auto v1 = dba->InsertVertex();
|
||||
auto v2 = dba->InsertVertex();
|
||||
auto edge_type = dba->EdgeType("edge_type");
|
||||
dba->InsertEdge(v1, v2, edge_type);
|
||||
dba->AdvanceCommand();
|
||||
EXPECT_EQ(2, CountIterable(dba->Vertices(false)));
|
||||
EXPECT_EQ(1, CountIterable(dba->Edges(false)));
|
||||
auto v1 = dba.InsertVertex();
|
||||
auto v2 = dba.InsertVertex();
|
||||
auto edge_type = dba.EdgeType("edge_type");
|
||||
dba.InsertEdge(v1, v2, edge_type);
|
||||
dba.AdvanceCommand();
|
||||
EXPECT_EQ(2, CountIterable(dba.Vertices(false)));
|
||||
EXPECT_EQ(1, CountIterable(dba.Edges(false)));
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
// OPTIONAL MATCH (n :missing)
|
||||
auto n = MakeScanAll(storage, symbol_table, "n");
|
||||
auto label_missing = dba->Label("missing");
|
||||
auto label_missing = dba.Label("missing");
|
||||
n.node_->labels_.emplace_back(label_missing);
|
||||
|
||||
auto *filter_expr =
|
||||
@ -1068,22 +1068,22 @@ TEST(QueryPlan, OptionalMatchThenExpandToMissingNode) {
|
||||
symbol_table[*m_ne->expression_] = m.sym_;
|
||||
symbol_table[*m_ne] = symbol_table.CreateSymbol("m", true);
|
||||
auto produce = MakeProduce(expand, m_ne);
|
||||
auto results = CollectProduce(produce.get(), symbol_table, *dba);
|
||||
auto results = CollectProduce(produce.get(), symbol_table, dba);
|
||||
EXPECT_EQ(0, results.size());
|
||||
}
|
||||
|
||||
TEST(QueryPlan, ExpandExistingNode) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
|
||||
// make a graph (v1)->(v2) that
|
||||
// has a recursive edge (v1)->(v1)
|
||||
auto v1 = dba->InsertVertex();
|
||||
auto v2 = dba->InsertVertex();
|
||||
auto edge_type = dba->EdgeType("Edge");
|
||||
dba->InsertEdge(v1, v1, edge_type);
|
||||
dba->InsertEdge(v1, v2, edge_type);
|
||||
dba->AdvanceCommand();
|
||||
auto v1 = dba.InsertVertex();
|
||||
auto v2 = dba.InsertVertex();
|
||||
auto edge_type = dba.EdgeType("Edge");
|
||||
dba.InsertEdge(v1, v1, edge_type);
|
||||
dba.InsertEdge(v1, v2, edge_type);
|
||||
dba.AdvanceCommand();
|
||||
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
@ -1093,10 +1093,9 @@ TEST(QueryPlan, ExpandExistingNode) {
|
||||
auto r_n = MakeExpand(storage, symbol_table, n.op_, n.sym_, "r",
|
||||
EdgeAtom::Direction::OUT, {}, "n", with_existing);
|
||||
if (with_existing)
|
||||
r_n.op_ =
|
||||
std::make_shared<Expand>(n.sym_, r_n.edge_sym_, r_n.edge_->direction_,
|
||||
std::vector<GraphDbTypes::EdgeType>{}, n.op_,
|
||||
n.sym_, with_existing);
|
||||
r_n.op_ = std::make_shared<Expand>(
|
||||
n.sym_, r_n.edge_sym_, r_n.edge_->direction_,
|
||||
std::vector<GraphDbTypes::EdgeType>{}, n.op_, n.sym_, with_existing);
|
||||
|
||||
// make a named expression and a produce
|
||||
auto output = NEXPR("n", IDENT("n"));
|
||||
@ -1105,7 +1104,7 @@ TEST(QueryPlan, ExpandExistingNode) {
|
||||
symbol_table.CreateSymbol("named_expression_1", true);
|
||||
auto produce = MakeProduce(r_n.op_, output);
|
||||
|
||||
auto results = CollectProduce(produce.get(), symbol_table, *dba);
|
||||
auto results = CollectProduce(produce.get(), symbol_table, dba);
|
||||
EXPECT_EQ(results.size(), expected_result_count);
|
||||
};
|
||||
|
||||
@ -1116,12 +1115,12 @@ TEST(QueryPlan, ExpandExistingNode) {
|
||||
TEST(QueryPlan, ExpandBothCycleEdgeCase) {
|
||||
// we're testing that expanding on BOTH
|
||||
// does only one expansion for a cycle
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
|
||||
auto v = dba->InsertVertex();
|
||||
dba->InsertEdge(v, v, dba->EdgeType("et"));
|
||||
dba->AdvanceCommand();
|
||||
auto v = dba.InsertVertex();
|
||||
dba.InsertEdge(v, v, dba.EdgeType("et"));
|
||||
dba.AdvanceCommand();
|
||||
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
@ -1129,12 +1128,12 @@ TEST(QueryPlan, ExpandBothCycleEdgeCase) {
|
||||
auto n = MakeScanAll(storage, symbol_table, "n");
|
||||
auto r_ = MakeExpand(storage, symbol_table, n.op_, n.sym_, "r",
|
||||
EdgeAtom::Direction::BOTH, {}, "_", false);
|
||||
EXPECT_EQ(1, PullAll(r_.op_, *dba, symbol_table));
|
||||
EXPECT_EQ(1, PullAll(r_.op_, dba, symbol_table));
|
||||
}
|
||||
|
||||
TEST(QueryPlan, EdgeFilter) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
|
||||
// make an N-star expanding from (v1)
|
||||
// where only one edge will qualify
|
||||
@ -1142,14 +1141,14 @@ TEST(QueryPlan, EdgeFilter) {
|
||||
// (edge_type yes|no) * (property yes|absent|no)
|
||||
std::vector<GraphDbTypes::EdgeType> edge_types;
|
||||
for (int j = 0; j < 2; ++j)
|
||||
edge_types.push_back(dba->EdgeType("et" + std::to_string(j)));
|
||||
edge_types.push_back(dba.EdgeType("et" + std::to_string(j)));
|
||||
std::vector<VertexAccessor> vertices;
|
||||
for (int i = 0; i < 7; ++i) vertices.push_back(dba->InsertVertex());
|
||||
for (int i = 0; i < 7; ++i) vertices.push_back(dba.InsertVertex());
|
||||
auto prop = PROPERTY_PAIR("property");
|
||||
std::vector<EdgeAccessor> edges;
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
edges.push_back(
|
||||
dba->InsertEdge(vertices[0], vertices[i + 1], edge_types[i % 2]));
|
||||
dba.InsertEdge(vertices[0], vertices[i + 1], edge_types[i % 2]));
|
||||
switch (i % 3) {
|
||||
case 0:
|
||||
edges.back().PropsSet(prop.second, 42);
|
||||
@ -1161,7 +1160,7 @@ TEST(QueryPlan, EdgeFilter) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
dba->AdvanceCommand();
|
||||
dba.AdvanceCommand();
|
||||
for (auto &vertex : vertices) vertex.Reconstruct();
|
||||
for (auto &edge : edges) edge.Reconstruct();
|
||||
|
||||
@ -1189,30 +1188,30 @@ TEST(QueryPlan, EdgeFilter) {
|
||||
symbol_table.CreateSymbol("named_expression_1", true);
|
||||
auto produce = MakeProduce(edge_filter, output);
|
||||
|
||||
return PullAll(produce, *dba, symbol_table);
|
||||
return PullAll(produce, dba, symbol_table);
|
||||
};
|
||||
|
||||
EXPECT_EQ(1, test_filter());
|
||||
// test that edge filtering always filters on old state
|
||||
for (auto &edge : edges) edge.PropsSet(prop.second, 42);
|
||||
EXPECT_EQ(1, test_filter());
|
||||
dba->AdvanceCommand();
|
||||
dba.AdvanceCommand();
|
||||
EXPECT_EQ(3, test_filter());
|
||||
}
|
||||
|
||||
TEST(QueryPlan, EdgeFilterMultipleTypes) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
|
||||
auto v1 = dba->InsertVertex();
|
||||
auto v2 = dba->InsertVertex();
|
||||
auto type_1 = dba->EdgeType("type_1");
|
||||
auto type_2 = dba->EdgeType("type_2");
|
||||
auto type_3 = dba->EdgeType("type_3");
|
||||
dba->InsertEdge(v1, v2, type_1);
|
||||
dba->InsertEdge(v1, v2, type_2);
|
||||
dba->InsertEdge(v1, v2, type_3);
|
||||
dba->AdvanceCommand();
|
||||
auto v1 = dba.InsertVertex();
|
||||
auto v2 = dba.InsertVertex();
|
||||
auto type_1 = dba.EdgeType("type_1");
|
||||
auto type_2 = dba.EdgeType("type_2");
|
||||
auto type_3 = dba.EdgeType("type_3");
|
||||
dba.InsertEdge(v1, v2, type_1);
|
||||
dba.InsertEdge(v1, v2, type_2);
|
||||
dba.InsertEdge(v1, v2, type_3);
|
||||
dba.AdvanceCommand();
|
||||
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
@ -1230,20 +1229,20 @@ TEST(QueryPlan, EdgeFilterMultipleTypes) {
|
||||
symbol_table[*output] = symbol_table.CreateSymbol("named_expression_1", true);
|
||||
symbol_table[*output->expression_] = r_m.node_sym_;
|
||||
|
||||
auto results = CollectProduce(produce.get(), symbol_table, *dba);
|
||||
auto results = CollectProduce(produce.get(), symbol_table, dba);
|
||||
EXPECT_EQ(results.size(), 2);
|
||||
}
|
||||
|
||||
TEST(QueryPlan, Filter) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
|
||||
// add a 6 nodes with property 'prop', 2 have true as value
|
||||
auto property = PROPERTY_PAIR("property");
|
||||
for (int i = 0; i < 6; ++i)
|
||||
dba->InsertVertex().PropsSet(property.second, i % 3 == 0);
|
||||
dba->InsertVertex(); // prop not set, gives NULL
|
||||
dba->AdvanceCommand();
|
||||
dba.InsertVertex().PropsSet(property.second, i % 3 == 0);
|
||||
dba.InsertVertex(); // prop not set, gives NULL
|
||||
dba.AdvanceCommand();
|
||||
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
@ -1260,20 +1259,20 @@ TEST(QueryPlan, Filter) {
|
||||
symbol_table[*output] = symbol_table.CreateSymbol("named_expression_1", true);
|
||||
auto produce = MakeProduce(f, output);
|
||||
|
||||
EXPECT_EQ(CollectProduce(produce.get(), symbol_table, *dba).size(), 2);
|
||||
EXPECT_EQ(CollectProduce(produce.get(), symbol_table, dba).size(), 2);
|
||||
}
|
||||
|
||||
TEST(QueryPlan, ExpandUniquenessFilter) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
|
||||
// make a graph that has (v1)->(v2) and a recursive edge (v1)->(v1)
|
||||
auto v1 = dba->InsertVertex();
|
||||
auto v2 = dba->InsertVertex();
|
||||
auto edge_type = dba->EdgeType("edge_type");
|
||||
dba->InsertEdge(v1, v2, edge_type);
|
||||
dba->InsertEdge(v1, v1, edge_type);
|
||||
dba->AdvanceCommand();
|
||||
auto v1 = dba.InsertVertex();
|
||||
auto v2 = dba.InsertVertex();
|
||||
auto edge_type = dba.EdgeType("edge_type");
|
||||
dba.InsertEdge(v1, v2, edge_type);
|
||||
dba.InsertEdge(v1, v1, edge_type);
|
||||
dba.AdvanceCommand();
|
||||
|
||||
auto check_expand_results = [&](bool vertex_uniqueness,
|
||||
bool edge_uniqueness) {
|
||||
@ -1298,7 +1297,7 @@ TEST(QueryPlan, ExpandUniquenessFilter) {
|
||||
last_op, r2_n3.node_sym_,
|
||||
std::vector<Symbol>{n1.sym_, r1_n2.node_sym_});
|
||||
|
||||
return PullAll(last_op, *dba, symbol_table);
|
||||
return PullAll(last_op, dba, symbol_table);
|
||||
};
|
||||
|
||||
EXPECT_EQ(2, check_expand_results(false, false));
|
||||
@ -1310,8 +1309,8 @@ TEST(QueryPlan, Distinct) {
|
||||
// test queries like
|
||||
// UNWIND [1, 2, 3, 3] AS x RETURN DISTINCT x
|
||||
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
|
||||
@ -1333,7 +1332,7 @@ TEST(QueryPlan, Distinct) {
|
||||
symbol_table[*x_ne] = symbol_table.CreateSymbol("x_ne", true);
|
||||
auto produce = MakeProduce(distinct, x_ne);
|
||||
|
||||
auto results = CollectProduce(produce.get(), symbol_table, *dba);
|
||||
auto results = CollectProduce(produce.get(), symbol_table, dba);
|
||||
ASSERT_EQ(output.size(), results.size());
|
||||
auto output_it = output.begin();
|
||||
for (const auto &row : results) {
|
||||
@ -1353,15 +1352,15 @@ TEST(QueryPlan, Distinct) {
|
||||
}
|
||||
|
||||
TEST(QueryPlan, ScanAllByLabel) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
// Add a vertex with a label and one without.
|
||||
auto label = dba->Label("label");
|
||||
auto labeled_vertex = dba->InsertVertex();
|
||||
auto label = dba.Label("label");
|
||||
auto labeled_vertex = dba.InsertVertex();
|
||||
labeled_vertex.add_label(label);
|
||||
dba->InsertVertex();
|
||||
dba->AdvanceCommand();
|
||||
EXPECT_EQ(2, CountIterable(dba->Vertices(false)));
|
||||
dba.InsertVertex();
|
||||
dba.AdvanceCommand();
|
||||
EXPECT_EQ(2, CountIterable(dba.Vertices(false)));
|
||||
// MATCH (n :label)
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
@ -1372,7 +1371,7 @@ TEST(QueryPlan, ScanAllByLabel) {
|
||||
auto produce = MakeProduce(scan_all_by_label.op_, output);
|
||||
symbol_table[*output->expression_] = scan_all_by_label.sym_;
|
||||
symbol_table[*output] = symbol_table.CreateSymbol("n", true);
|
||||
auto results = CollectProduce(produce.get(), symbol_table, *dba);
|
||||
auto results = CollectProduce(produce.get(), symbol_table, dba);
|
||||
ASSERT_EQ(results.size(), 1);
|
||||
auto result_row = results[0];
|
||||
ASSERT_EQ(result_row.size(), 1);
|
||||
@ -1380,12 +1379,10 @@ TEST(QueryPlan, ScanAllByLabel) {
|
||||
}
|
||||
|
||||
TEST(QueryPlan, ScanAllByLabelProperty) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
// Add 5 vertices with same label, but with different property values.
|
||||
auto label = dba->Label("label");
|
||||
auto prop = dba->Property("prop");
|
||||
|
||||
auto label = GraphDbAccessor(db).Label("label");
|
||||
auto prop = GraphDbAccessor(db).Property("prop");
|
||||
// vertex property values that will be stored into the DB
|
||||
// clang-format off
|
||||
std::vector<TypedValue> values{
|
||||
@ -1393,18 +1390,18 @@ TEST(QueryPlan, ScanAllByLabelProperty) {
|
||||
std::vector<TypedValue>{0}, std::vector<TypedValue>{1},
|
||||
std::vector<TypedValue>{2}};
|
||||
// clang-format on
|
||||
|
||||
for (const auto &value : values) {
|
||||
auto vertex = dba->InsertVertex();
|
||||
vertex.add_label(label);
|
||||
vertex.PropsSet(prop, value);
|
||||
{
|
||||
GraphDbAccessor dba(db);
|
||||
for (const auto &value : values) {
|
||||
auto vertex = dba.InsertVertex();
|
||||
vertex.add_label(label);
|
||||
vertex.PropsSet(prop, value);
|
||||
}
|
||||
dba.Commit();
|
||||
GraphDbAccessor(db).BuildIndex(label, prop);
|
||||
}
|
||||
dba->Commit();
|
||||
dba = dbms.active();
|
||||
dba->BuildIndex(label, prop);
|
||||
dba->Commit();
|
||||
dba = dbms.active();
|
||||
ASSERT_EQ(14, CountIterable(dba->Vertices(false)));
|
||||
GraphDbAccessor dba(db);
|
||||
ASSERT_EQ(14, CountIterable(dba.Vertices(false)));
|
||||
|
||||
auto check = [&dba, label, prop](TypedValue lower, Bound::Type lower_type,
|
||||
TypedValue upper, Bound::Type upper_type,
|
||||
@ -1419,7 +1416,7 @@ TEST(QueryPlan, ScanAllByLabelProperty) {
|
||||
auto produce = MakeProduce(scan_all.op_, output);
|
||||
symbol_table[*output->expression_] = scan_all.sym_;
|
||||
symbol_table[*output] = symbol_table.CreateSymbol("n", true);
|
||||
auto results = CollectProduce(produce.get(), symbol_table, *dba);
|
||||
auto results = CollectProduce(produce.get(), symbol_table, dba);
|
||||
ASSERT_EQ(results.size(), expected.size());
|
||||
for (size_t i = 0; i < expected.size(); i++) {
|
||||
TypedValue equal =
|
||||
@ -1452,23 +1449,24 @@ TEST(QueryPlan, ScanAllByLabelProperty) {
|
||||
}
|
||||
|
||||
TEST(QueryPlan, ScanAllByLabelPropertyEqualityNoError) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
// Add 2 vertices with same label, but with property values that cannot be
|
||||
// compared. On the other hand, equality works fine.
|
||||
auto label = dba->Label("label");
|
||||
auto prop = dba->Property("prop");
|
||||
auto number_vertex = dba->InsertVertex();
|
||||
number_vertex.add_label(label);
|
||||
number_vertex.PropsSet(prop, 42);
|
||||
auto string_vertex = dba->InsertVertex();
|
||||
string_vertex.add_label(label);
|
||||
string_vertex.PropsSet(prop, "string");
|
||||
dba->Commit();
|
||||
dba = dbms.active();
|
||||
dba->BuildIndex(label, prop);
|
||||
dba = dbms.active();
|
||||
EXPECT_EQ(2, CountIterable(dba->Vertices(false)));
|
||||
auto label = GraphDbAccessor(db).Label("label");
|
||||
auto prop = GraphDbAccessor(db).Property("prop");
|
||||
{
|
||||
GraphDbAccessor dba(db);
|
||||
auto number_vertex = dba.InsertVertex();
|
||||
number_vertex.add_label(label);
|
||||
number_vertex.PropsSet(prop, 42);
|
||||
auto string_vertex = dba.InsertVertex();
|
||||
string_vertex.add_label(label);
|
||||
string_vertex.PropsSet(prop, "string");
|
||||
dba.Commit();
|
||||
GraphDbAccessor(db).BuildIndex(label, prop);
|
||||
}
|
||||
GraphDbAccessor dba(db);
|
||||
EXPECT_EQ(2, CountIterable(dba.Vertices(false)));
|
||||
// MATCH (n :label {prop: 42})
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
@ -1479,7 +1477,7 @@ TEST(QueryPlan, ScanAllByLabelPropertyEqualityNoError) {
|
||||
auto produce = MakeProduce(scan_all.op_, output);
|
||||
symbol_table[*output->expression_] = scan_all.sym_;
|
||||
symbol_table[*output] = symbol_table.CreateSymbol("n", true);
|
||||
auto results = CollectProduce(produce.get(), symbol_table, *dba);
|
||||
auto results = CollectProduce(produce.get(), symbol_table, dba);
|
||||
ASSERT_EQ(results.size(), 1);
|
||||
const auto &row = results[0];
|
||||
ASSERT_EQ(row.size(), 1);
|
||||
@ -1490,24 +1488,25 @@ TEST(QueryPlan, ScanAllByLabelPropertyEqualityNoError) {
|
||||
}
|
||||
|
||||
TEST(QueryPlan, ScanAllByLabelPropertyEqualNull) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
// Add 2 vertices with the same label, but one has a property value while
|
||||
// the
|
||||
// other does not. Checking if the value is equal to null, should yield no
|
||||
// results.
|
||||
auto label = dba->Label("label");
|
||||
auto prop = dba->Property("prop");
|
||||
auto vertex = dba->InsertVertex();
|
||||
vertex.add_label(label);
|
||||
auto vertex_with_prop = dba->InsertVertex();
|
||||
vertex_with_prop.add_label(label);
|
||||
vertex_with_prop.PropsSet(prop, 42);
|
||||
dba->Commit();
|
||||
dba = dbms.active();
|
||||
dba->BuildIndex(label, prop);
|
||||
dba = dbms.active();
|
||||
EXPECT_EQ(2, CountIterable(dba->Vertices(false)));
|
||||
auto label = GraphDbAccessor(db).Label("label");
|
||||
auto prop = GraphDbAccessor(db).Property("prop");
|
||||
{
|
||||
GraphDbAccessor dba(db);
|
||||
auto vertex = dba.InsertVertex();
|
||||
vertex.add_label(label);
|
||||
auto vertex_with_prop = dba.InsertVertex();
|
||||
vertex_with_prop.add_label(label);
|
||||
vertex_with_prop.PropsSet(prop, 42);
|
||||
dba.Commit();
|
||||
GraphDbAccessor(db).BuildIndex(label, prop);
|
||||
}
|
||||
GraphDbAccessor dba(db);
|
||||
EXPECT_EQ(2, CountIterable(dba.Vertices(false)));
|
||||
// MATCH (n :label {prop: 42})
|
||||
AstTreeStorage storage;
|
||||
SymbolTable symbol_table;
|
||||
@ -1518,7 +1517,7 @@ TEST(QueryPlan, ScanAllByLabelPropertyEqualNull) {
|
||||
auto produce = MakeProduce(scan_all.op_, output);
|
||||
symbol_table[*output->expression_] = scan_all.sym_;
|
||||
symbol_table[*output] = symbol_table.CreateSymbol("n", true);
|
||||
auto results = CollectProduce(produce.get(), symbol_table, *dba);
|
||||
auto results = CollectProduce(produce.get(), symbol_table, dba);
|
||||
EXPECT_EQ(results.size(), 0);
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,6 @@
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "database/dbms.hpp"
|
||||
#include "query/frontend/ast/ast.hpp"
|
||||
#include "query/frontend/semantic/symbol_generator.hpp"
|
||||
#include "query/frontend/semantic/symbol_table.hpp"
|
||||
@ -320,9 +319,9 @@ auto CheckPlan(LogicalOperator &plan, const SymbolTable &symbol_table,
|
||||
template <class... TChecker>
|
||||
auto CheckPlan(AstTreeStorage &storage, TChecker... checker) {
|
||||
auto symbol_table = MakeSymbolTable(*storage.query());
|
||||
Dbms dbms;
|
||||
auto planning_context =
|
||||
MakePlanningContext(storage, symbol_table, *dbms.active());
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto planning_context = MakePlanningContext(storage, symbol_table, dba);
|
||||
auto plan = MakeLogicalPlan<RuleBasedPlanner>(planning_context);
|
||||
CheckPlan(*plan, symbol_table, checker...);
|
||||
}
|
||||
@ -341,9 +340,9 @@ TEST(TestLogicalPlanner, CreateNodeReturn) {
|
||||
auto query = QUERY(CREATE(PATTERN(NODE("n"))), RETURN(ident_n, AS("n")));
|
||||
auto symbol_table = MakeSymbolTable(*query);
|
||||
auto acc = ExpectAccumulate({symbol_table.at(*ident_n)});
|
||||
Dbms dbms;
|
||||
auto planning_context =
|
||||
MakePlanningContext(storage, symbol_table, *dbms.active());
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto planning_context = MakePlanningContext(storage, symbol_table, dba);
|
||||
auto plan = MakeLogicalPlan<RuleBasedPlanner>(planning_context);
|
||||
CheckPlan(*plan, symbol_table, ExpectCreateNode(), acc, ExpectProduce());
|
||||
}
|
||||
@ -351,9 +350,9 @@ TEST(TestLogicalPlanner, CreateNodeReturn) {
|
||||
TEST(TestLogicalPlanner, CreateExpand) {
|
||||
// Test CREATE (n) -[r :rel1]-> (m)
|
||||
AstTreeStorage storage;
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto relationship = dba->EdgeType("relationship");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto relationship = dba.EdgeType("relationship");
|
||||
QUERY(CREATE(PATTERN(NODE("n"), EDGE("r", Direction::OUT, {relationship}),
|
||||
NODE("m"))));
|
||||
CheckPlan(storage, ExpectCreateNode(), ExpectCreateExpand());
|
||||
@ -369,9 +368,9 @@ TEST(TestLogicalPlanner, CreateMultipleNode) {
|
||||
TEST(TestLogicalPlanner, CreateNodeExpandNode) {
|
||||
// Test CREATE (n) -[r :rel]-> (m), (l)
|
||||
AstTreeStorage storage;
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto relationship = dba->EdgeType("rel");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto relationship = dba.EdgeType("rel");
|
||||
QUERY(CREATE(
|
||||
PATTERN(NODE("n"), EDGE("r", Direction::OUT, {relationship}), NODE("m")),
|
||||
PATTERN(NODE("l"))));
|
||||
@ -382,9 +381,9 @@ TEST(TestLogicalPlanner, CreateNodeExpandNode) {
|
||||
TEST(TestLogicalPlanner, CreateNamedPattern) {
|
||||
// Test CREATE p = (n) -[r :rel]-> (m)
|
||||
AstTreeStorage storage;
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto relationship = dba->EdgeType("rel");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto relationship = dba.EdgeType("rel");
|
||||
QUERY(CREATE(NAMED_PATTERN(
|
||||
"p", NODE("n"), EDGE("r", Direction::OUT, {relationship}), NODE("m"))));
|
||||
CheckPlan(storage, ExpectCreateNode(), ExpectCreateExpand(),
|
||||
@ -394,9 +393,9 @@ TEST(TestLogicalPlanner, CreateNamedPattern) {
|
||||
TEST(TestLogicalPlanner, MatchCreateExpand) {
|
||||
// Test MATCH (n) CREATE (n) -[r :rel1]-> (m)
|
||||
AstTreeStorage storage;
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto relationship = dba->EdgeType("relationship");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto relationship = dba.EdgeType("relationship");
|
||||
QUERY(MATCH(PATTERN(NODE("n"))),
|
||||
CREATE(PATTERN(NODE("n"), EDGE("r", Direction::OUT, {relationship}),
|
||||
NODE("m"))));
|
||||
@ -406,9 +405,9 @@ TEST(TestLogicalPlanner, MatchCreateExpand) {
|
||||
TEST(TestLogicalPlanner, MatchLabeledNodes) {
|
||||
// Test MATCH (n :label) RETURN n
|
||||
AstTreeStorage storage;
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto label = dba->Label("label");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto label = dba.Label("label");
|
||||
QUERY(MATCH(PATTERN(NODE("n", label))), RETURN("n"));
|
||||
CheckPlan(storage, ExpectScanAllByLabel(), ExpectProduce());
|
||||
}
|
||||
@ -416,9 +415,9 @@ TEST(TestLogicalPlanner, MatchLabeledNodes) {
|
||||
TEST(TestLogicalPlanner, MatchPathReturn) {
|
||||
// Test MATCH (n) -[r :relationship]- (m) RETURN n
|
||||
AstTreeStorage storage;
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto relationship = dba->EdgeType("relationship");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto relationship = dba.EdgeType("relationship");
|
||||
QUERY(MATCH(PATTERN(NODE("n"), EDGE("r", Direction::BOTH, {relationship}),
|
||||
NODE("m"))),
|
||||
RETURN("n"));
|
||||
@ -428,9 +427,9 @@ TEST(TestLogicalPlanner, MatchPathReturn) {
|
||||
TEST(TestLogicalPlanner, MatchNamedPatternReturn) {
|
||||
// Test MATCH p = (n) -[r :relationship]- (m) RETURN p
|
||||
AstTreeStorage storage;
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto relationship = dba->EdgeType("relationship");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto relationship = dba.EdgeType("relationship");
|
||||
QUERY(MATCH(NAMED_PATTERN("p", NODE("n"),
|
||||
EDGE("r", Direction::BOTH, {relationship}),
|
||||
NODE("m"))),
|
||||
@ -442,9 +441,9 @@ TEST(TestLogicalPlanner, MatchNamedPatternReturn) {
|
||||
TEST(TestLogicalPlanner, MatchNamedPatternWithPredicateReturn) {
|
||||
// Test MATCH p = (n) -[r :relationship]- (m) RETURN p
|
||||
AstTreeStorage storage;
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto relationship = dba->EdgeType("relationship");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto relationship = dba.EdgeType("relationship");
|
||||
QUERY(MATCH(NAMED_PATTERN("p", NODE("n"),
|
||||
EDGE("r", Direction::BOTH, {relationship}),
|
||||
NODE("m"))),
|
||||
@ -456,9 +455,9 @@ TEST(TestLogicalPlanner, MatchNamedPatternWithPredicateReturn) {
|
||||
TEST(TestLogicalPlanner, MatchWhereReturn) {
|
||||
// Test MATCH (n) WHERE n.property < 42 RETURN n
|
||||
AstTreeStorage storage;
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto property = dba->Property("property");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto property = dba.Property("property");
|
||||
QUERY(MATCH(PATTERN(NODE("n"))),
|
||||
WHERE(LESS(PROPERTY_LOOKUP("n", property), LITERAL(42))), RETURN("n"));
|
||||
CheckPlan(storage, ExpectScanAll(), ExpectFilter(), ExpectProduce());
|
||||
@ -474,10 +473,10 @@ TEST(TestLogicalPlanner, MatchDelete) {
|
||||
TEST(TestLogicalPlanner, MatchNodeSet) {
|
||||
// Test MATCH (n) SET n.prop = 42, n = n, n :label
|
||||
AstTreeStorage storage;
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto prop = dba->Property("prop");
|
||||
auto label = dba->Label("label");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto prop = dba.Property("prop");
|
||||
auto label = dba.Label("label");
|
||||
QUERY(MATCH(PATTERN(NODE("n"))), SET(PROPERTY_LOOKUP("n", prop), LITERAL(42)),
|
||||
SET("n", IDENT("n")), SET("n", {label}));
|
||||
CheckPlan(storage, ExpectScanAll(), ExpectSetProperty(),
|
||||
@ -487,10 +486,10 @@ TEST(TestLogicalPlanner, MatchNodeSet) {
|
||||
TEST(TestLogicalPlanner, MatchRemove) {
|
||||
// Test MATCH (n) REMOVE n.prop REMOVE n :label
|
||||
AstTreeStorage storage;
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto prop = dba->Property("prop");
|
||||
auto label = dba->Label("label");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto prop = dba.Property("prop");
|
||||
auto label = dba.Label("label");
|
||||
QUERY(MATCH(PATTERN(NODE("n"))), REMOVE(PROPERTY_LOOKUP("n", prop)),
|
||||
REMOVE("n", {label}));
|
||||
CheckPlan(storage, ExpectScanAll(), ExpectRemoveProperty(),
|
||||
@ -566,9 +565,9 @@ TEST(TestLogicalPlanner, MatchWithReturn) {
|
||||
|
||||
TEST(TestLogicalPlanner, MatchWithWhereReturn) {
|
||||
// Test MATCH (old) WITH old AS new WHERE new.prop < 42 RETURN new
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto prop = dba->Property("prop");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto prop = dba.Property("prop");
|
||||
AstTreeStorage storage;
|
||||
QUERY(MATCH(PATTERN(NODE("old"))), WITH("old", AS("new")),
|
||||
WHERE(LESS(PROPERTY_LOOKUP("new", prop), LITERAL(42))), RETURN("new"));
|
||||
@ -579,10 +578,10 @@ TEST(TestLogicalPlanner, MatchWithWhereReturn) {
|
||||
|
||||
TEST(TestLogicalPlanner, CreateMultiExpand) {
|
||||
// Test CREATE (n) -[r :r]-> (m), (n) - [p :p]-> (l)
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto r = dba->EdgeType("r");
|
||||
auto p = dba->EdgeType("p");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto r = dba.EdgeType("r");
|
||||
auto p = dba.EdgeType("p");
|
||||
AstTreeStorage storage;
|
||||
QUERY(CREATE(PATTERN(NODE("n"), EDGE("r", Direction::OUT, {r}), NODE("m")),
|
||||
PATTERN(NODE("n"), EDGE("p", Direction::OUT, {p}), NODE("l"))));
|
||||
@ -593,9 +592,9 @@ TEST(TestLogicalPlanner, CreateMultiExpand) {
|
||||
TEST(TestLogicalPlanner, MatchWithSumWhereReturn) {
|
||||
// Test MATCH (n) WITH SUM(n.prop) + 42 AS sum WHERE sum < 42
|
||||
// RETURN sum AS result
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto prop = dba->Property("prop");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto prop = dba.Property("prop");
|
||||
AstTreeStorage storage;
|
||||
auto sum = SUM(PROPERTY_LOOKUP("n", prop));
|
||||
auto literal = LITERAL(42);
|
||||
@ -608,10 +607,10 @@ TEST(TestLogicalPlanner, MatchWithSumWhereReturn) {
|
||||
|
||||
TEST(TestLogicalPlanner, MatchReturnSum) {
|
||||
// Test MATCH (n) RETURN SUM(n.prop1) AS sum, n.prop2 AS group
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto prop1 = dba->Property("prop1");
|
||||
auto prop2 = dba->Property("prop2");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto prop1 = dba.Property("prop1");
|
||||
auto prop2 = dba.Property("prop2");
|
||||
AstTreeStorage storage;
|
||||
auto sum = SUM(PROPERTY_LOOKUP("n", prop1));
|
||||
auto n_prop2 = PROPERTY_LOOKUP("n", prop2);
|
||||
@ -623,9 +622,9 @@ TEST(TestLogicalPlanner, MatchReturnSum) {
|
||||
|
||||
TEST(TestLogicalPlanner, CreateWithSum) {
|
||||
// Test CREATE (n) WITH SUM(n.prop) AS sum
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto prop = dba->Property("prop");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto prop = dba.Property("prop");
|
||||
AstTreeStorage storage;
|
||||
auto n_prop = PROPERTY_LOOKUP("n", prop);
|
||||
auto sum = SUM(n_prop);
|
||||
@ -633,7 +632,7 @@ TEST(TestLogicalPlanner, CreateWithSum) {
|
||||
auto symbol_table = MakeSymbolTable(*query);
|
||||
auto acc = ExpectAccumulate({symbol_table.at(*n_prop->expression_)});
|
||||
auto aggr = ExpectAggregate({sum}, {});
|
||||
auto planning_context = MakePlanningContext(storage, symbol_table, *dba);
|
||||
auto planning_context = MakePlanningContext(storage, symbol_table, dba);
|
||||
auto plan = MakeLogicalPlan<RuleBasedPlanner>(planning_context);
|
||||
// We expect both the accumulation and aggregation because the part before
|
||||
// WITH updates the database.
|
||||
@ -643,9 +642,9 @@ TEST(TestLogicalPlanner, CreateWithSum) {
|
||||
|
||||
TEST(TestLogicalPlanner, MatchWithCreate) {
|
||||
// Test MATCH (n) WITH n AS a CREATE (a) -[r :r]-> (b)
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto r_type = dba->EdgeType("r");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto r_type = dba.EdgeType("r");
|
||||
AstTreeStorage storage;
|
||||
QUERY(MATCH(PATTERN(NODE("n"))), WITH("n", AS("a")),
|
||||
CREATE(PATTERN(NODE("a"), EDGE("r", Direction::OUT, {r_type}),
|
||||
@ -671,9 +670,9 @@ TEST(TestLogicalPlanner, CreateWithSkipReturnLimit) {
|
||||
RETURN("m", LIMIT(LITERAL(1))));
|
||||
auto symbol_table = MakeSymbolTable(*query);
|
||||
auto acc = ExpectAccumulate({symbol_table.at(*ident_n)});
|
||||
Dbms dbms;
|
||||
auto planning_context =
|
||||
MakePlanningContext(storage, symbol_table, *dbms.active());
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto planning_context = MakePlanningContext(storage, symbol_table, dba);
|
||||
auto plan = MakeLogicalPlan<RuleBasedPlanner>(planning_context);
|
||||
// Since we have a write query, we need to have Accumulate. This is a bit
|
||||
// different than Neo4j 3.0, which optimizes WITH followed by RETURN as a
|
||||
@ -686,9 +685,9 @@ TEST(TestLogicalPlanner, CreateWithSkipReturnLimit) {
|
||||
|
||||
TEST(TestLogicalPlanner, CreateReturnSumSkipLimit) {
|
||||
// Test CREATE (n) RETURN SUM(n.prop) AS s SKIP 2 LIMIT 1
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto prop = dba->Property("prop");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto prop = dba.Property("prop");
|
||||
AstTreeStorage storage;
|
||||
auto n_prop = PROPERTY_LOOKUP("n", prop);
|
||||
auto sum = SUM(n_prop);
|
||||
@ -697,7 +696,7 @@ TEST(TestLogicalPlanner, CreateReturnSumSkipLimit) {
|
||||
auto symbol_table = MakeSymbolTable(*query);
|
||||
auto acc = ExpectAccumulate({symbol_table.at(*n_prop->expression_)});
|
||||
auto aggr = ExpectAggregate({sum}, {});
|
||||
auto planning_context = MakePlanningContext(storage, symbol_table, *dba);
|
||||
auto planning_context = MakePlanningContext(storage, symbol_table, dba);
|
||||
auto plan = MakeLogicalPlan<RuleBasedPlanner>(planning_context);
|
||||
CheckPlan(*plan, symbol_table, ExpectCreateNode(), acc, aggr, ExpectProduce(),
|
||||
ExpectSkip(), ExpectLimit());
|
||||
@ -705,9 +704,9 @@ TEST(TestLogicalPlanner, CreateReturnSumSkipLimit) {
|
||||
|
||||
TEST(TestLogicalPlanner, MatchReturnOrderBy) {
|
||||
// Test MATCH (n) RETURN n ORDER BY n.prop
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto prop = dba->Property("prop");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto prop = dba.Property("prop");
|
||||
AstTreeStorage storage;
|
||||
auto ret = RETURN("n", ORDER_BY(PROPERTY_LOOKUP("n", prop)));
|
||||
QUERY(MATCH(PATTERN(NODE("n"))), ret);
|
||||
@ -717,10 +716,10 @@ TEST(TestLogicalPlanner, MatchReturnOrderBy) {
|
||||
TEST(TestLogicalPlanner, CreateWithOrderByWhere) {
|
||||
// Test CREATE (n) -[r :r]-> (m)
|
||||
// WITH n AS new ORDER BY new.prop, r.prop WHERE m.prop < 42
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto prop = dba->Property("prop");
|
||||
auto r_type = dba->EdgeType("r");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto prop = dba.Property("prop");
|
||||
auto r_type = dba.EdgeType("r");
|
||||
AstTreeStorage storage;
|
||||
auto ident_n = IDENT("n");
|
||||
auto new_prop = PROPERTY_LOOKUP("new", prop);
|
||||
@ -738,7 +737,7 @@ TEST(TestLogicalPlanner, CreateWithOrderByWhere) {
|
||||
symbol_table.at(*r_prop->expression_), // `r` in ORDER BY
|
||||
symbol_table.at(*m_prop->expression_), // `m` in WHERE
|
||||
});
|
||||
auto planning_context = MakePlanningContext(storage, symbol_table, *dba);
|
||||
auto planning_context = MakePlanningContext(storage, symbol_table, dba);
|
||||
auto plan = MakeLogicalPlan<RuleBasedPlanner>(planning_context);
|
||||
CheckPlan(*plan, symbol_table, ExpectCreateNode(), ExpectCreateExpand(), acc,
|
||||
ExpectProduce(), ExpectOrderBy(), ExpectFilter());
|
||||
@ -758,10 +757,10 @@ TEST(TestLogicalPlanner, MatchMerge) {
|
||||
// Test MATCH (n) MERGE (n) -[r :r]- (m)
|
||||
// ON MATCH SET n.prop = 42 ON CREATE SET m = n
|
||||
// RETURN n AS n
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto r_type = dba->EdgeType("r");
|
||||
auto prop = dba->Property("prop");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto r_type = dba.EdgeType("r");
|
||||
auto prop = dba.Property("prop");
|
||||
AstTreeStorage storage;
|
||||
auto ident_n = IDENT("n");
|
||||
auto query = QUERY(
|
||||
@ -777,7 +776,7 @@ TEST(TestLogicalPlanner, MatchMerge) {
|
||||
auto symbol_table = MakeSymbolTable(*query);
|
||||
// We expect Accumulate after Merge, because it is considered as a write.
|
||||
auto acc = ExpectAccumulate({symbol_table.at(*ident_n)});
|
||||
auto planning_context = MakePlanningContext(storage, symbol_table, *dba);
|
||||
auto planning_context = MakePlanningContext(storage, symbol_table, dba);
|
||||
auto plan = MakeLogicalPlan<RuleBasedPlanner>(planning_context);
|
||||
CheckPlan(*plan, symbol_table, ExpectScanAll(),
|
||||
ExpectMerge(on_match, on_create), acc, ExpectProduce());
|
||||
@ -789,9 +788,9 @@ TEST(TestLogicalPlanner, MatchMerge) {
|
||||
|
||||
TEST(TestLogicalPlanner, MatchOptionalMatchWhereReturn) {
|
||||
// Test MATCH (n) OPTIONAL MATCH (n) -[r]- (m) WHERE m.prop < 42 RETURN r
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto prop = dba->Property("prop");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto prop = dba.Property("prop");
|
||||
AstTreeStorage storage;
|
||||
QUERY(MATCH(PATTERN(NODE("n"))),
|
||||
OPTIONAL_MATCH(PATTERN(NODE("n"), EDGE("r"), NODE("m"))),
|
||||
@ -822,9 +821,9 @@ TEST(TestLogicalPlanner, ReturnDistinctOrderBySkipLimit) {
|
||||
|
||||
TEST(TestLogicalPlanner, CreateWithDistinctSumWhereReturn) {
|
||||
// Test CREATE (n) WITH DISTINCT SUM(n.prop) AS s WHERE s < 42 RETURN s
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto prop = dba->Property("prop");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto prop = dba.Property("prop");
|
||||
AstTreeStorage storage;
|
||||
auto node_n = NODE("n");
|
||||
auto sum = SUM(PROPERTY_LOOKUP("n", prop));
|
||||
@ -833,7 +832,7 @@ TEST(TestLogicalPlanner, CreateWithDistinctSumWhereReturn) {
|
||||
auto symbol_table = MakeSymbolTable(*query);
|
||||
auto acc = ExpectAccumulate({symbol_table.at(*node_n->identifier_)});
|
||||
auto aggr = ExpectAggregate({sum}, {});
|
||||
auto planning_context = MakePlanningContext(storage, symbol_table, *dba);
|
||||
auto planning_context = MakePlanningContext(storage, symbol_table, dba);
|
||||
auto plan = MakeLogicalPlan<RuleBasedPlanner>(planning_context);
|
||||
CheckPlan(*plan, symbol_table, ExpectCreateNode(), acc, aggr, ExpectProduce(),
|
||||
ExpectDistinct(), ExpectFilter(), ExpectProduce());
|
||||
@ -841,8 +840,8 @@ TEST(TestLogicalPlanner, CreateWithDistinctSumWhereReturn) {
|
||||
|
||||
TEST(TestLogicalPlanner, MatchCrossReferenceVariable) {
|
||||
// Test MATCH (n {prop: m.prop}), (m {prop: n.prop}) RETURN n
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto prop = PROPERTY_PAIR("prop");
|
||||
AstTreeStorage storage;
|
||||
auto node_n = NODE("n");
|
||||
@ -860,9 +859,9 @@ TEST(TestLogicalPlanner, MatchCrossReferenceVariable) {
|
||||
|
||||
TEST(TestLogicalPlanner, MatchWhereBeforeExpand) {
|
||||
// Test MATCH (n) -[r]- (m) WHERE n.prop < 42 RETURN n
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto prop = dba->Property("prop");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto prop = dba.Property("prop");
|
||||
AstTreeStorage storage;
|
||||
QUERY(MATCH(PATTERN(NODE("n"), EDGE("r"), NODE("m"))),
|
||||
WHERE(LESS(PROPERTY_LOOKUP("n", prop), LITERAL(42))), RETURN("n"));
|
||||
@ -873,9 +872,9 @@ TEST(TestLogicalPlanner, MatchWhereBeforeExpand) {
|
||||
|
||||
TEST(TestLogicalPlanner, MultiMatchWhere) {
|
||||
// Test MATCH (n) -[r]- (m) MATCH (l) WHERE n.prop < 42 RETURN n
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto prop = dba->Property("prop");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto prop = dba.Property("prop");
|
||||
AstTreeStorage storage;
|
||||
QUERY(MATCH(PATTERN(NODE("n"), EDGE("r"), NODE("m"))),
|
||||
MATCH(PATTERN(NODE("l"))),
|
||||
@ -888,9 +887,9 @@ TEST(TestLogicalPlanner, MultiMatchWhere) {
|
||||
|
||||
TEST(TestLogicalPlanner, MatchOptionalMatchWhere) {
|
||||
// Test MATCH (n) -[r]- (m) OPTIONAL MATCH (l) WHERE n.prop < 42 RETURN n
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto prop = dba->Property("prop");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto prop = dba.Property("prop");
|
||||
AstTreeStorage storage;
|
||||
QUERY(MATCH(PATTERN(NODE("n"), EDGE("r"), NODE("m"))),
|
||||
OPTIONAL_MATCH(PATTERN(NODE("l"))),
|
||||
@ -905,15 +904,15 @@ TEST(TestLogicalPlanner, MatchOptionalMatchWhere) {
|
||||
|
||||
TEST(TestLogicalPlanner, MatchReturnAsterisk) {
|
||||
// Test MATCH (n) -[e]- (m) RETURN *, m.prop
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto prop = dba->Property("prop");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto prop = dba.Property("prop");
|
||||
AstTreeStorage storage;
|
||||
auto ret = RETURN(PROPERTY_LOOKUP("m", prop), AS("m.prop"));
|
||||
ret->body_.all_identifiers = true;
|
||||
auto query = QUERY(MATCH(PATTERN(NODE("n"), EDGE("e"), NODE("m"))), ret);
|
||||
auto symbol_table = MakeSymbolTable(*query);
|
||||
auto planning_context = MakePlanningContext(storage, symbol_table, *dba);
|
||||
auto planning_context = MakePlanningContext(storage, symbol_table, dba);
|
||||
auto plan = MakeLogicalPlan<RuleBasedPlanner>(planning_context);
|
||||
CheckPlan(*plan, symbol_table, ExpectScanAll(), ExpectExpand(),
|
||||
ExpectProduce());
|
||||
@ -927,16 +926,16 @@ TEST(TestLogicalPlanner, MatchReturnAsterisk) {
|
||||
|
||||
TEST(TestLogicalPlanner, MatchReturnAsteriskSum) {
|
||||
// Test MATCH (n) RETURN *, SUM(n.prop) AS s
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto prop = dba->Property("prop");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto prop = dba.Property("prop");
|
||||
AstTreeStorage storage;
|
||||
auto sum = SUM(PROPERTY_LOOKUP("n", prop));
|
||||
auto ret = RETURN(sum, AS("s"));
|
||||
ret->body_.all_identifiers = true;
|
||||
auto query = QUERY(MATCH(PATTERN(NODE("n"))), ret);
|
||||
auto symbol_table = MakeSymbolTable(*query);
|
||||
auto planning_context = MakePlanningContext(storage, symbol_table, *dba);
|
||||
auto planning_context = MakePlanningContext(storage, symbol_table, dba);
|
||||
auto plan = MakeLogicalPlan<RuleBasedPlanner>(planning_context);
|
||||
auto *produce = dynamic_cast<Produce *>(plan.get());
|
||||
ASSERT_TRUE(produce);
|
||||
@ -957,8 +956,8 @@ TEST(TestLogicalPlanner, MatchReturnAsteriskSum) {
|
||||
|
||||
TEST(TestLogicalPlanner, UnwindMergeNodeProperty) {
|
||||
// Test UNWIND [1] AS i MERGE (n {prop: i})
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
AstTreeStorage storage;
|
||||
auto node_n = NODE("n");
|
||||
node_n->properties_[PROPERTY_PAIR("prop")] = IDENT("i");
|
||||
@ -1011,8 +1010,8 @@ TEST(TestLogicalPlanner, ListLiteralAggregationReturn) {
|
||||
TEST(TestLogicalPlanner, MapLiteralAggregationReturn) {
|
||||
// Test RETURN {sum: SUM(2)} AS result, 42 AS group_by
|
||||
AstTreeStorage storage;
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto sum = SUM(LITERAL(2));
|
||||
auto group_by_literal = LITERAL(42);
|
||||
QUERY(RETURN(MAP({PROPERTY_PAIR("sum"), sum}), AS("result"), group_by_literal,
|
||||
@ -1052,10 +1051,10 @@ TEST(TestLogicalPlanner, ListSliceAggregationReturn) {
|
||||
|
||||
TEST(TestLogicalPlanner, CreateIndex) {
|
||||
// Test CREATE INDEX ON :Label(property)
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto label = dba->Label("label");
|
||||
auto property = dba->Property("property");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto label = dba.Label("label");
|
||||
auto property = dba.Property("property");
|
||||
AstTreeStorage storage;
|
||||
QUERY(CREATE_INDEX_ON(label, property));
|
||||
CheckPlan(storage, ExpectCreateIndex(label, property));
|
||||
@ -1064,124 +1063,129 @@ TEST(TestLogicalPlanner, CreateIndex) {
|
||||
TEST(TestLogicalPlanner, AtomIndexedLabelProperty) {
|
||||
// Test MATCH (n :label {property: 42, not_indexed: 0}) RETURN n
|
||||
AstTreeStorage storage;
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto label = dba->Label("label");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto label = dba.Label("label");
|
||||
auto property = PROPERTY_PAIR("property");
|
||||
auto not_indexed = PROPERTY_PAIR("not_indexed");
|
||||
auto vertex = dba->InsertVertex();
|
||||
auto vertex = dba.InsertVertex();
|
||||
vertex.add_label(label);
|
||||
vertex.PropsSet(property.second, 42);
|
||||
dba->Commit();
|
||||
dba = dbms.active();
|
||||
dba->BuildIndex(label, property.second);
|
||||
dba = dbms.active();
|
||||
auto node = NODE("n", label);
|
||||
auto lit_42 = LITERAL(42);
|
||||
node->properties_[property] = lit_42;
|
||||
node->properties_[not_indexed] = LITERAL(0);
|
||||
QUERY(MATCH(PATTERN(node)), RETURN("n"));
|
||||
auto symbol_table = MakeSymbolTable(*storage.query());
|
||||
auto planning_context = MakePlanningContext(storage, symbol_table, *dba);
|
||||
auto plan = MakeLogicalPlan<RuleBasedPlanner>(planning_context);
|
||||
CheckPlan(*plan, symbol_table,
|
||||
ExpectScanAllByLabelPropertyValue(label, property, lit_42),
|
||||
ExpectFilter(), ExpectProduce());
|
||||
dba.Commit();
|
||||
GraphDbAccessor(db).BuildIndex(label, property.second);
|
||||
{
|
||||
GraphDbAccessor dba(db);
|
||||
auto node = NODE("n", label);
|
||||
auto lit_42 = LITERAL(42);
|
||||
node->properties_[property] = lit_42;
|
||||
node->properties_[not_indexed] = LITERAL(0);
|
||||
QUERY(MATCH(PATTERN(node)), RETURN("n"));
|
||||
auto symbol_table = MakeSymbolTable(*storage.query());
|
||||
auto planning_context = MakePlanningContext(storage, symbol_table, dba);
|
||||
auto plan = MakeLogicalPlan<RuleBasedPlanner>(planning_context);
|
||||
CheckPlan(*plan, symbol_table,
|
||||
ExpectScanAllByLabelPropertyValue(label, property, lit_42),
|
||||
ExpectFilter(), ExpectProduce());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TestLogicalPlanner, AtomPropertyWhereLabelIndexing) {
|
||||
// Test MATCH (n {property: 42}) WHERE n.not_indexed AND n:label RETURN n
|
||||
AstTreeStorage storage;
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto label = dba->Label("label");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto label = dba.Label("label");
|
||||
auto property = PROPERTY_PAIR("property");
|
||||
auto not_indexed = PROPERTY_PAIR("not_indexed");
|
||||
dba->BuildIndex(label, property.second);
|
||||
dba = dbms.active();
|
||||
auto node = NODE("n");
|
||||
auto lit_42 = LITERAL(42);
|
||||
node->properties_[property] = lit_42;
|
||||
QUERY(MATCH(PATTERN(node)),
|
||||
WHERE(AND(PROPERTY_LOOKUP("n", not_indexed),
|
||||
storage.Create<query::LabelsTest>(
|
||||
IDENT("n"), std::vector<GraphDbTypes::Label>{label}))),
|
||||
RETURN("n"));
|
||||
auto symbol_table = MakeSymbolTable(*storage.query());
|
||||
auto planning_context = MakePlanningContext(storage, symbol_table, *dba);
|
||||
auto plan = MakeLogicalPlan<RuleBasedPlanner>(planning_context);
|
||||
CheckPlan(*plan, symbol_table,
|
||||
ExpectScanAllByLabelPropertyValue(label, property, lit_42),
|
||||
ExpectFilter(), ExpectProduce());
|
||||
dba.BuildIndex(label, property.second);
|
||||
{
|
||||
GraphDbAccessor dba(db);
|
||||
auto node = NODE("n");
|
||||
auto lit_42 = LITERAL(42);
|
||||
node->properties_[property] = lit_42;
|
||||
QUERY(MATCH(PATTERN(node)),
|
||||
WHERE(AND(PROPERTY_LOOKUP("n", not_indexed),
|
||||
storage.Create<query::LabelsTest>(
|
||||
IDENT("n"), std::vector<GraphDbTypes::Label>{label}))),
|
||||
RETURN("n"));
|
||||
auto symbol_table = MakeSymbolTable(*storage.query());
|
||||
auto planning_context = MakePlanningContext(storage, symbol_table, dba);
|
||||
auto plan = MakeLogicalPlan<RuleBasedPlanner>(planning_context);
|
||||
CheckPlan(*plan, symbol_table,
|
||||
ExpectScanAllByLabelPropertyValue(label, property, lit_42),
|
||||
ExpectFilter(), ExpectProduce());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TestLogicalPlanner, WhereIndexedLabelProperty) {
|
||||
// Test MATCH (n :label) WHERE n.property = 42 RETURN n
|
||||
AstTreeStorage storage;
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto label = dba->Label("label");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto label = dba.Label("label");
|
||||
auto property = PROPERTY_PAIR("property");
|
||||
dba->BuildIndex(label, property.second);
|
||||
dba = dbms.active();
|
||||
auto lit_42 = LITERAL(42);
|
||||
QUERY(MATCH(PATTERN(NODE("n", label))),
|
||||
WHERE(EQ(PROPERTY_LOOKUP("n", property), lit_42)), RETURN("n"));
|
||||
auto symbol_table = MakeSymbolTable(*storage.query());
|
||||
auto planning_context = MakePlanningContext(storage, symbol_table, *dba);
|
||||
auto plan = MakeLogicalPlan<RuleBasedPlanner>(planning_context);
|
||||
CheckPlan(*plan, symbol_table,
|
||||
ExpectScanAllByLabelPropertyValue(label, property, lit_42),
|
||||
ExpectProduce());
|
||||
dba.BuildIndex(label, property.second);
|
||||
{
|
||||
GraphDbAccessor dba(db);
|
||||
auto lit_42 = LITERAL(42);
|
||||
QUERY(MATCH(PATTERN(NODE("n", label))),
|
||||
WHERE(EQ(PROPERTY_LOOKUP("n", property), lit_42)), RETURN("n"));
|
||||
auto symbol_table = MakeSymbolTable(*storage.query());
|
||||
auto planning_context = MakePlanningContext(storage, symbol_table, dba);
|
||||
auto plan = MakeLogicalPlan<RuleBasedPlanner>(planning_context);
|
||||
CheckPlan(*plan, symbol_table,
|
||||
ExpectScanAllByLabelPropertyValue(label, property, lit_42),
|
||||
ExpectProduce());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TestLogicalPlanner, BestPropertyIndexed) {
|
||||
// Test MATCH (n :label) WHERE n.property = 1 AND n.better = 42 RETURN n
|
||||
AstTreeStorage storage;
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto label = dba->Label("label");
|
||||
auto property = dba->Property("property");
|
||||
dba->BuildIndex(label, property);
|
||||
dba = dbms.active();
|
||||
// Add a vertex with :label+property combination, so that the best
|
||||
// :label+better remains empty and thus better choice.
|
||||
auto vertex = dba->InsertVertex();
|
||||
vertex.add_label(label);
|
||||
vertex.PropsSet(property, 1);
|
||||
dba->Commit();
|
||||
dba = dbms.active();
|
||||
ASSERT_EQ(dba->VerticesCount(label, property), 1);
|
||||
GraphDb db;
|
||||
auto label = GraphDbAccessor(db).Label("label");
|
||||
auto property = GraphDbAccessor(db).Property("property");
|
||||
{
|
||||
GraphDbAccessor(db).BuildIndex(label, property);
|
||||
GraphDbAccessor dba(db);
|
||||
// Add a vertex with :label+property combination, so that the best
|
||||
// :label+better remains empty and thus better choice.
|
||||
auto vertex = dba.InsertVertex();
|
||||
vertex.add_label(label);
|
||||
vertex.PropsSet(property, 1);
|
||||
dba.Commit();
|
||||
}
|
||||
ASSERT_EQ(GraphDbAccessor(db).VerticesCount(label, property), 1);
|
||||
auto better = PROPERTY_PAIR("better");
|
||||
dba->BuildIndex(label, better.second);
|
||||
dba = dbms.active();
|
||||
ASSERT_EQ(dba->VerticesCount(label, better.second), 0);
|
||||
auto lit_42 = LITERAL(42);
|
||||
QUERY(MATCH(PATTERN(NODE("n", label))),
|
||||
WHERE(AND(EQ(PROPERTY_LOOKUP("n", property), LITERAL(1)),
|
||||
EQ(PROPERTY_LOOKUP("n", better), lit_42))),
|
||||
RETURN("n"));
|
||||
auto symbol_table = MakeSymbolTable(*storage.query());
|
||||
auto planning_context = MakePlanningContext(storage, symbol_table, *dba);
|
||||
auto plan = MakeLogicalPlan<RuleBasedPlanner>(planning_context);
|
||||
CheckPlan(*plan, symbol_table,
|
||||
ExpectScanAllByLabelPropertyValue(label, better, lit_42),
|
||||
ExpectFilter(), ExpectProduce());
|
||||
GraphDbAccessor(db).BuildIndex(label, better.second);
|
||||
{
|
||||
GraphDbAccessor dba(db);
|
||||
ASSERT_EQ(dba.VerticesCount(label, better.second), 0);
|
||||
auto lit_42 = LITERAL(42);
|
||||
QUERY(MATCH(PATTERN(NODE("n", label))),
|
||||
WHERE(AND(EQ(PROPERTY_LOOKUP("n", property), LITERAL(1)),
|
||||
EQ(PROPERTY_LOOKUP("n", better), lit_42))),
|
||||
RETURN("n"));
|
||||
auto symbol_table = MakeSymbolTable(*storage.query());
|
||||
auto planning_context = MakePlanningContext(storage, symbol_table, dba);
|
||||
auto plan = MakeLogicalPlan<RuleBasedPlanner>(planning_context);
|
||||
CheckPlan(*plan, symbol_table,
|
||||
ExpectScanAllByLabelPropertyValue(label, better, lit_42),
|
||||
ExpectFilter(), ExpectProduce());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TestLogicalPlanner, MultiPropertyIndexScan) {
|
||||
// Test MATCH (n :label1), (m :label2) WHERE n.prop1 = 1 AND m.prop2 = 2
|
||||
// RETURN n, m
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto label1 = dba->Label("label1");
|
||||
auto label2 = dba->Label("label2");
|
||||
GraphDb db;
|
||||
auto label1 = GraphDbAccessor(db).Label("label1");
|
||||
auto label2 = GraphDbAccessor(db).Label("label2");
|
||||
auto prop1 = PROPERTY_PAIR("prop1");
|
||||
auto prop2 = PROPERTY_PAIR("prop2");
|
||||
dba->BuildIndex(label1, prop1.second);
|
||||
dba = dbms.active();
|
||||
dba->BuildIndex(label2, prop2.second);
|
||||
dba = dbms.active();
|
||||
GraphDbAccessor(db).BuildIndex(label1, prop1.second);
|
||||
GraphDbAccessor(db).BuildIndex(label2, prop2.second);
|
||||
GraphDbAccessor dba(db);
|
||||
AstTreeStorage storage;
|
||||
auto lit_1 = LITERAL(1);
|
||||
auto lit_2 = LITERAL(2);
|
||||
@ -1190,7 +1194,7 @@ TEST(TestLogicalPlanner, MultiPropertyIndexScan) {
|
||||
EQ(PROPERTY_LOOKUP("m", prop2), lit_2))),
|
||||
RETURN("n", "m"));
|
||||
auto symbol_table = MakeSymbolTable(*storage.query());
|
||||
auto planning_context = MakePlanningContext(storage, symbol_table, *dba);
|
||||
auto planning_context = MakePlanningContext(storage, symbol_table, dba);
|
||||
auto plan = MakeLogicalPlan<RuleBasedPlanner>(planning_context);
|
||||
CheckPlan(*plan, symbol_table,
|
||||
ExpectScanAllByLabelPropertyValue(label1, prop1, lit_1),
|
||||
@ -1201,12 +1205,11 @@ TEST(TestLogicalPlanner, MultiPropertyIndexScan) {
|
||||
TEST(TestLogicalPlanner, WhereIndexedLabelPropertyRange) {
|
||||
// Test MATCH (n :label) WHERE n.property REL_OP 42 RETURN n
|
||||
// REL_OP is one of: `<`, `<=`, `>`, `>=`
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto label = dba->Label("label");
|
||||
auto property = dba->Property("property");
|
||||
dba->BuildIndex(label, property);
|
||||
dba = dbms.active();
|
||||
GraphDb db;
|
||||
auto label = GraphDbAccessor(db).Label("label");
|
||||
auto property = GraphDbAccessor(db).Property("property");
|
||||
GraphDbAccessor(db).BuildIndex(label, property);
|
||||
GraphDbAccessor dba(db);
|
||||
AstTreeStorage storage;
|
||||
auto lit_42 = LITERAL(42);
|
||||
auto n_prop = PROPERTY_LOOKUP("n", property);
|
||||
@ -1217,7 +1220,7 @@ TEST(TestLogicalPlanner, WhereIndexedLabelPropertyRange) {
|
||||
AstTreeStorage storage;
|
||||
QUERY(MATCH(PATTERN(NODE("n", label))), WHERE(rel_expr), RETURN("n"));
|
||||
auto symbol_table = MakeSymbolTable(*storage.query());
|
||||
auto planning_context = MakePlanningContext(storage, symbol_table, *dba);
|
||||
auto planning_context = MakePlanningContext(storage, symbol_table, dba);
|
||||
auto plan = MakeLogicalPlan<RuleBasedPlanner>(planning_context);
|
||||
CheckPlan(*plan, symbol_table,
|
||||
ExpectScanAllByLabelPropertyRange(label, property, lower_bound,
|
||||
@ -1252,24 +1255,26 @@ TEST(TestLogicalPlanner, WhereIndexedLabelPropertyRange) {
|
||||
|
||||
TEST(TestLogicalPlanner, UnableToUsePropertyIndex) {
|
||||
// Test MATCH (n: label) WHERE n.property = n.property RETURN n
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto label = dba->Label("label");
|
||||
auto property = dba->Property("property");
|
||||
dba->BuildIndex(label, property);
|
||||
dba = dbms.active();
|
||||
AstTreeStorage storage;
|
||||
QUERY(
|
||||
MATCH(PATTERN(NODE("n", label))),
|
||||
WHERE(EQ(PROPERTY_LOOKUP("n", property), PROPERTY_LOOKUP("n", property))),
|
||||
RETURN("n"));
|
||||
auto symbol_table = MakeSymbolTable(*storage.query());
|
||||
auto planning_context = MakePlanningContext(storage, symbol_table, *dba);
|
||||
auto plan = MakeLogicalPlan<RuleBasedPlanner>(planning_context);
|
||||
// We can only get ScanAllByLabelIndex, because we are comparing properties
|
||||
// with those on the same node.
|
||||
CheckPlan(*plan, symbol_table, ExpectScanAllByLabel(), ExpectFilter(),
|
||||
ExpectProduce());
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto label = dba.Label("label");
|
||||
auto property = dba.Property("property");
|
||||
dba.BuildIndex(label, property);
|
||||
{
|
||||
GraphDbAccessor dba(db);
|
||||
AstTreeStorage storage;
|
||||
QUERY(MATCH(PATTERN(NODE("n", label))),
|
||||
WHERE(EQ(PROPERTY_LOOKUP("n", property),
|
||||
PROPERTY_LOOKUP("n", property))),
|
||||
RETURN("n"));
|
||||
auto symbol_table = MakeSymbolTable(*storage.query());
|
||||
auto planning_context = MakePlanningContext(storage, symbol_table, dba);
|
||||
auto plan = MakeLogicalPlan<RuleBasedPlanner>(planning_context);
|
||||
// We can only get ScanAllByLabelIndex, because we are comparing properties
|
||||
// with those on the same node.
|
||||
CheckPlan(*plan, symbol_table, ExpectScanAllByLabel(), ExpectFilter(),
|
||||
ExpectProduce());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TestLogicalPlanner, ReturnSumGroupByAll) {
|
||||
@ -1301,9 +1306,9 @@ TEST(TestLogicalPlanner, MatchExpandVariableNoBounds) {
|
||||
|
||||
TEST(TestLogicalPlanner, MatchExpandVariableInlinedFilter) {
|
||||
// Test MATCH (n) -[r :type * {prop: 42}]-> (m) RETURN r
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto type = dba->EdgeType("type");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto type = dba.EdgeType("type");
|
||||
auto prop = PROPERTY_PAIR("prop");
|
||||
AstTreeStorage storage;
|
||||
auto edge = EDGE_VARIABLE("r", Direction::BOTH, {type});
|
||||
@ -1316,9 +1321,9 @@ TEST(TestLogicalPlanner, MatchExpandVariableInlinedFilter) {
|
||||
|
||||
TEST(TestLogicalPlanner, MatchExpandVariableNotInlinedFilter) {
|
||||
// Test MATCH (n) -[r :type * {prop: m.prop}]-> (m) RETURN r
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto type = dba->EdgeType("type");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto type = dba.EdgeType("type");
|
||||
auto prop = PROPERTY_PAIR("prop");
|
||||
AstTreeStorage storage;
|
||||
auto edge = EDGE_VARIABLE("r", Direction::BOTH, {type});
|
||||
@ -1342,9 +1347,9 @@ TEST(TestLogicalPlanner, UnwindMatchVariable) {
|
||||
|
||||
TEST(TestLogicalPlanner, MatchBreadthFirst) {
|
||||
// Test MATCH (n) -[r:type *..10 (r, n|n)]-> (m) RETURN r
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto edge_type = dba->EdgeType("type");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto edge_type = dba.EdgeType("type");
|
||||
AstTreeStorage storage;
|
||||
auto *bfs = storage.Create<query::EdgeAtom>(
|
||||
IDENT("r"), query::EdgeAtom::Type::BREADTH_FIRST, Direction::OUT,
|
||||
@ -1360,14 +1365,13 @@ TEST(TestLogicalPlanner, MatchBreadthFirst) {
|
||||
|
||||
TEST(TestLogicalPlanner, MatchDoubleScanToExpandExisting) {
|
||||
// Test MATCH (n) -[r]- (m :label) RETURN r
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto label = dba->Label("label");
|
||||
dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto label = dba.Label("label");
|
||||
AstTreeStorage storage;
|
||||
QUERY(MATCH(PATTERN(NODE("n"), EDGE("r"), NODE("m", label))), RETURN("r"));
|
||||
auto symbol_table = MakeSymbolTable(*storage.query());
|
||||
auto planning_context = MakePlanningContext(storage, symbol_table, *dba);
|
||||
auto planning_context = MakePlanningContext(storage, symbol_table, dba);
|
||||
auto plan = MakeLogicalPlan<RuleBasedPlanner>(planning_context);
|
||||
// We expect 2x ScanAll and then Expand, since we are guessing that is
|
||||
// faster (due to low label index vertex count).
|
||||
@ -1377,41 +1381,42 @@ TEST(TestLogicalPlanner, MatchDoubleScanToExpandExisting) {
|
||||
|
||||
TEST(TestLogicalPlanner, MatchScanToExpand) {
|
||||
// Test MATCH (n) -[r]- (m :label {property: 1}) RETURN r
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto label = dba->Label("label");
|
||||
auto property = dba->Property("property");
|
||||
dba->BuildIndex(label, property);
|
||||
dba = dbms.active();
|
||||
GraphDb db;
|
||||
auto label = GraphDbAccessor(db).Label("label");
|
||||
auto property = GraphDbAccessor(db).Property("property");
|
||||
GraphDbAccessor(db).BuildIndex(label, property);
|
||||
GraphDbAccessor dba(db);
|
||||
// Fill vertices to the max.
|
||||
for (int64_t i = 0; i < FLAGS_query_vertex_count_to_expand_existing; ++i) {
|
||||
auto vertex = dba->InsertVertex();
|
||||
auto vertex = dba.InsertVertex();
|
||||
vertex.PropsSet(property, 1);
|
||||
vertex.add_label(label);
|
||||
}
|
||||
// Add one more above the max.
|
||||
auto vertex = dba->InsertVertex();
|
||||
auto vertex = dba.InsertVertex();
|
||||
vertex.add_label(label);
|
||||
vertex.PropsSet(property, 1);
|
||||
dba->Commit();
|
||||
dba = dbms.active();
|
||||
AstTreeStorage storage;
|
||||
auto node_m = NODE("m", label);
|
||||
node_m->properties_[std::make_pair("property", property)] = LITERAL(1);
|
||||
QUERY(MATCH(PATTERN(NODE("n"), EDGE("r"), node_m)), RETURN("r"));
|
||||
auto symbol_table = MakeSymbolTable(*storage.query());
|
||||
auto planning_context = MakePlanningContext(storage, symbol_table, *dba);
|
||||
auto plan = MakeLogicalPlan<RuleBasedPlanner>(planning_context);
|
||||
// We expect 1x ScanAllByLabel and then Expand, since we are guessing that is
|
||||
// faster (due to high label index vertex count).
|
||||
CheckPlan(*plan, symbol_table, ExpectScanAll(), ExpectExpand(),
|
||||
ExpectFilter(), ExpectProduce());
|
||||
dba.Commit();
|
||||
{
|
||||
GraphDbAccessor dba(db);
|
||||
AstTreeStorage storage;
|
||||
auto node_m = NODE("m", label);
|
||||
node_m->properties_[std::make_pair("property", property)] = LITERAL(1);
|
||||
QUERY(MATCH(PATTERN(NODE("n"), EDGE("r"), node_m)), RETURN("r"));
|
||||
auto symbol_table = MakeSymbolTable(*storage.query());
|
||||
auto planning_context = MakePlanningContext(storage, symbol_table, dba);
|
||||
auto plan = MakeLogicalPlan<RuleBasedPlanner>(planning_context);
|
||||
// We expect 1x ScanAllByLabel and then Expand, since we are guessing that
|
||||
// is faster (due to high label index vertex count).
|
||||
CheckPlan(*plan, symbol_table, ExpectScanAll(), ExpectExpand(),
|
||||
ExpectFilter(), ExpectProduce());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TestLogicalPlanner, MatchWhereAndSplit) {
|
||||
// Test MATCH (n) -[r]- (m) WHERE n.prop AND r.prop RETURN m
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto prop = PROPERTY_PAIR("prop");
|
||||
AstTreeStorage storage;
|
||||
QUERY(MATCH(PATTERN(NODE("n"), EDGE("r"), NODE("m"))),
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "database/dbms.hpp"
|
||||
#include "query/frontend/ast/ast.hpp"
|
||||
#include "query/frontend/semantic/symbol_generator.hpp"
|
||||
#include "query/frontend/semantic/symbol_table.hpp"
|
||||
@ -85,8 +84,8 @@ TEST(TestSymbolGenerator, CreatePropertyUnbound) {
|
||||
AstTreeStorage storage;
|
||||
// AST with unbound variable in create: CREATE ({prop: x})
|
||||
auto node = NODE("anon");
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
node->properties_[PROPERTY_PAIR("prop")] = IDENT("x");
|
||||
auto query_ast = QUERY(CREATE(PATTERN(node)));
|
||||
SymbolGenerator symbol_generator(symbol_table);
|
||||
@ -151,9 +150,9 @@ TEST(TestSymbolGenerator, MatchCreateRedeclareEdge) {
|
||||
AstTreeStorage storage;
|
||||
// AST with redeclaring a match edge variable in create:
|
||||
// MATCH (n) -[r]- (m) CREATE (n) -[r :relationship]-> (l)
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto relationship = dba->EdgeType("relationship");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto relationship = dba.EdgeType("relationship");
|
||||
auto query =
|
||||
QUERY(MATCH(PATTERN(NODE("n"), EDGE("r"), NODE("m"))),
|
||||
CREATE(PATTERN(NODE("n"),
|
||||
@ -190,10 +189,10 @@ TEST(TestSymbolGenerator, CreateMultipleEdgeType) {
|
||||
AstTreeStorage storage;
|
||||
// Multiple edge relationship are not allowed when creating edges.
|
||||
// CREATE (n) -[r :rel1 | :rel2]-> (m)
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto rel1 = dba->EdgeType("rel1");
|
||||
auto rel2 = dba->EdgeType("rel2");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto rel1 = dba.EdgeType("rel1");
|
||||
auto rel2 = dba.EdgeType("rel2");
|
||||
auto edge = EDGE("r", EdgeAtom::Direction::OUT, {rel1});
|
||||
edge->edge_types_.emplace_back(rel2);
|
||||
auto query = QUERY(CREATE(PATTERN(NODE("n"), edge, NODE("m"))));
|
||||
@ -206,9 +205,9 @@ TEST(TestSymbolGenerator, CreateBidirectionalEdge) {
|
||||
AstTreeStorage storage;
|
||||
// Bidirectional relationships are not allowed when creating edges.
|
||||
// CREATE (n) -[r :rel1]- (m)
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto rel1 = dba->EdgeType("rel1");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto rel1 = dba.EdgeType("rel1");
|
||||
auto query = QUERY(CREATE(PATTERN(
|
||||
NODE("n"), EDGE("r", EdgeAtom::Direction::BOTH, {rel1}), NODE("m"))));
|
||||
SymbolTable symbol_table;
|
||||
@ -290,9 +289,9 @@ TEST(TestSymbolGenerator, MatchWithReturnUnbound) {
|
||||
|
||||
TEST(TestSymbolGenerator, MatchWithWhere) {
|
||||
// Test MATCH (old) WITH old AS n WHERE n.prop < 42
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto prop = dba->Property("prop");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto prop = dba.Property("prop");
|
||||
AstTreeStorage storage;
|
||||
auto node = NODE("old");
|
||||
auto old_ident = IDENT("old");
|
||||
@ -316,9 +315,9 @@ TEST(TestSymbolGenerator, MatchWithWhere) {
|
||||
|
||||
TEST(TestSymbolGenerator, MatchWithWhereUnbound) {
|
||||
// Test MATCH (old) WITH COUNT(old) AS c WHERE old.prop < 42
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto prop = dba->Property("prop");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto prop = dba.Property("prop");
|
||||
AstTreeStorage storage;
|
||||
auto query =
|
||||
QUERY(MATCH(PATTERN(NODE("old"))), WITH(COUNT(IDENT("old")), AS("c")),
|
||||
@ -330,10 +329,10 @@ TEST(TestSymbolGenerator, MatchWithWhereUnbound) {
|
||||
|
||||
TEST(TestSymbolGenerator, CreateMultiExpand) {
|
||||
// Test CREATE (n) -[r :r]-> (m), (n) - [p :p]-> (l)
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto r_type = dba->EdgeType("r");
|
||||
auto p_type = dba->EdgeType("p");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto r_type = dba.EdgeType("r");
|
||||
auto p_type = dba.EdgeType("p");
|
||||
AstTreeStorage storage;
|
||||
auto node_n1 = NODE("n");
|
||||
auto edge_r = EDGE("r", EdgeAtom::Direction::OUT, {r_type});
|
||||
@ -368,10 +367,10 @@ TEST(TestSymbolGenerator, CreateMultiExpand) {
|
||||
|
||||
TEST(TestSymbolGenerator, MatchCreateExpandLabel) {
|
||||
// Test MATCH (n) CREATE (m) -[r :r]-> (n:label)
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto r_type = dba->EdgeType("r");
|
||||
auto label = dba->Label("label");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto r_type = dba.EdgeType("r");
|
||||
auto label = dba.Label("label");
|
||||
AstTreeStorage storage;
|
||||
auto query = QUERY(
|
||||
MATCH(PATTERN(NODE("n"))),
|
||||
@ -384,9 +383,9 @@ TEST(TestSymbolGenerator, MatchCreateExpandLabel) {
|
||||
|
||||
TEST(TestSymbolGenerator, CreateExpandProperty) {
|
||||
// Test CREATE (n) -[r :r]-> (n {prop: 42})
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto r_type = dba->EdgeType("r");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto r_type = dba.EdgeType("r");
|
||||
AstTreeStorage storage;
|
||||
auto n_prop = NODE("n");
|
||||
n_prop->properties_[PROPERTY_PAIR("prop")] = LITERAL(42);
|
||||
@ -399,9 +398,9 @@ TEST(TestSymbolGenerator, CreateExpandProperty) {
|
||||
|
||||
TEST(TestSymbolGenerator, MatchReturnSum) {
|
||||
// Test MATCH (n) RETURN SUM(n.prop) + 42 AS result
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto prop = dba->Property("prop");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto prop = dba.Property("prop");
|
||||
AstTreeStorage storage;
|
||||
auto node = NODE("n");
|
||||
auto sum = SUM(PROPERTY_LOOKUP("n", prop));
|
||||
@ -423,9 +422,9 @@ TEST(TestSymbolGenerator, MatchReturnSum) {
|
||||
|
||||
TEST(TestSymbolGenerator, NestedAggregation) {
|
||||
// Test MATCH (n) RETURN SUM(42 + SUM(n.prop)) AS s
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto prop = dba->Property("prop");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto prop = dba.Property("prop");
|
||||
AstTreeStorage storage;
|
||||
auto query = QUERY(
|
||||
MATCH(PATTERN(NODE("n"))),
|
||||
@ -437,9 +436,9 @@ TEST(TestSymbolGenerator, NestedAggregation) {
|
||||
|
||||
TEST(TestSymbolGenerator, WrongAggregationContext) {
|
||||
// Test MATCH (n) WITH n.prop AS prop WHERE SUM(prop) < 42
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto prop = dba->Property("prop");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto prop = dba.Property("prop");
|
||||
AstTreeStorage storage;
|
||||
auto query = QUERY(MATCH(PATTERN(NODE("n"))),
|
||||
WITH(PROPERTY_LOOKUP("n", prop), AS("prop")),
|
||||
@ -451,8 +450,8 @@ TEST(TestSymbolGenerator, WrongAggregationContext) {
|
||||
|
||||
TEST(TestSymbolGenerator, MatchPropCreateNodeProp) {
|
||||
// Test MATCH (n) CREATE (m {prop: n.prop})
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto prop = PROPERTY_PAIR("prop");
|
||||
AstTreeStorage storage;
|
||||
auto node_n = NODE("n");
|
||||
@ -473,9 +472,9 @@ TEST(TestSymbolGenerator, MatchPropCreateNodeProp) {
|
||||
|
||||
TEST(TestSymbolGenerator, CreateNodeEdge) {
|
||||
// Test CREATE (n), (n) -[r :r]-> (n)
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto r_type = dba->EdgeType("r");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto r_type = dba.EdgeType("r");
|
||||
AstTreeStorage storage;
|
||||
auto node_1 = NODE("n");
|
||||
auto node_2 = NODE("n");
|
||||
@ -495,9 +494,9 @@ TEST(TestSymbolGenerator, CreateNodeEdge) {
|
||||
|
||||
TEST(TestSymbolGenerator, MatchWithCreate) {
|
||||
// Test MATCH (n) WITH n AS m CREATE (m) -[r :r]-> (m)
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto r_type = dba->EdgeType("r");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto r_type = dba.EdgeType("r");
|
||||
AstTreeStorage storage;
|
||||
auto node_1 = NODE("n");
|
||||
auto node_2 = NODE("m");
|
||||
@ -643,9 +642,9 @@ TEST(TestSymbolGenerator, MergeVariableError) {
|
||||
}
|
||||
// Test MATCH (n) -[r]- (m) MERGE (a) -[r :rel]- (b)
|
||||
{
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto rel = dba->EdgeType("rel");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto rel = dba.EdgeType("rel");
|
||||
AstTreeStorage storage;
|
||||
auto query = QUERY(
|
||||
MATCH(PATTERN(NODE("n"), EDGE("r"), NODE("m"))),
|
||||
@ -670,10 +669,10 @@ TEST(TestSymbolGenerator, MergeEdgeWithoutType) {
|
||||
TEST(TestSymbolGenerator, MergeOnMatchOnCreate) {
|
||||
// Test MATCH (n) MERGE (n) -[r :rel]- (m) ON MATCH SET n.prop = 42
|
||||
// ON CREATE SET m.prop = 42 RETURN r AS r
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto rel = dba->EdgeType("rel");
|
||||
auto prop = dba->Property("prop");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto rel = dba.EdgeType("rel");
|
||||
auto prop = dba.Property("prop");
|
||||
AstTreeStorage storage;
|
||||
auto match_n = NODE("n");
|
||||
auto merge_n = NODE("n");
|
||||
@ -745,8 +744,8 @@ TEST(TestSymbolGenerator, WithUnwindReturn) {
|
||||
|
||||
TEST(TestSymbolGenerator, MatchCrossReferenceVariable) {
|
||||
// MATCH (n {prop: m.prop}), (m {prop: n.prop}) RETURN n
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto prop = PROPERTY_PAIR("prop");
|
||||
AstTreeStorage storage;
|
||||
auto node_n = NODE("n");
|
||||
@ -776,9 +775,9 @@ TEST(TestSymbolGenerator, MatchCrossReferenceVariable) {
|
||||
|
||||
TEST(TestSymbolGenerator, MatchWithAsteriskReturnAsterisk) {
|
||||
// MATCH (n) -[e]- (m) WITH * RETURN *, n.prop
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto prop = dba->Property("prop");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto prop = dba.Property("prop");
|
||||
AstTreeStorage storage;
|
||||
auto n_prop = PROPERTY_LOOKUP("n", prop);
|
||||
auto ret = RETURN(n_prop, AS("n.prop"));
|
||||
@ -824,10 +823,10 @@ TEST(TestSymbolGenerator, MatchReturnAsteriskNoUserVariables) {
|
||||
|
||||
TEST(TestSymbolGenerator, MatchMergeExpandLabel) {
|
||||
// Test MATCH (n) MERGE (m) -[r :r]-> (n:label)
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto r_type = dba->EdgeType("r");
|
||||
auto label = dba->Label("label");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto r_type = dba.EdgeType("r");
|
||||
auto label = dba.Label("label");
|
||||
AstTreeStorage storage;
|
||||
auto query = QUERY(
|
||||
MATCH(PATTERN(NODE("n"))),
|
||||
@ -840,8 +839,8 @@ TEST(TestSymbolGenerator, MatchMergeExpandLabel) {
|
||||
|
||||
TEST(TestSymbolGenerator, MatchEdgeWithIdentifierInProperty) {
|
||||
// Test MATCH (n) -[r {prop: n.prop}]- (m) RETURN r
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto prop = PROPERTY_PAIR("prop");
|
||||
AstTreeStorage storage;
|
||||
auto edge = EDGE("r");
|
||||
@ -860,9 +859,9 @@ TEST(TestSymbolGenerator, MatchEdgeWithIdentifierInProperty) {
|
||||
|
||||
TEST(TestSymbolGenerator, MatchVariablePathUsingIdentifier) {
|
||||
// Test MATCH (n) -[r *..l.prop]- (m), (l) RETURN r
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto prop = dba->Property("prop");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto prop = dba.Property("prop");
|
||||
AstTreeStorage storage;
|
||||
auto edge = EDGE_VARIABLE("r");
|
||||
auto l_prop = PROPERTY_LOOKUP("l", prop);
|
||||
@ -884,9 +883,9 @@ TEST(TestSymbolGenerator, MatchVariablePathUsingIdentifier) {
|
||||
|
||||
TEST(TestSymbolGenerator, MatchVariablePathUsingUnboundIdentifier) {
|
||||
// Test MATCH (n) -[r *..l.prop]- (m) MATCH (l) RETURN r
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto prop = dba->Property("prop");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto prop = dba.Property("prop");
|
||||
AstTreeStorage storage;
|
||||
auto edge = EDGE_VARIABLE("r");
|
||||
auto l_prop = PROPERTY_LOOKUP("l", prop);
|
||||
@ -938,9 +937,9 @@ TEST(TestSymbolGenerator, VariablePathSameIdentifier) {
|
||||
// Test MATCH (n) -[r *r.prop..]-> (m) RETURN r raises UnboundVariableError.
|
||||
// `r` cannot be used inside the range expression, since it is bound by the
|
||||
// variable expansion itself.
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto prop = dba->Property("prop");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto prop = dba.Property("prop");
|
||||
AstTreeStorage storage;
|
||||
auto edge = EDGE_VARIABLE("r", EdgeAtom::Direction::OUT);
|
||||
edge->lower_bound_ = PROPERTY_LOOKUP("r", prop);
|
||||
@ -954,8 +953,8 @@ TEST(TestSymbolGenerator, MatchPropertySameIdentifier) {
|
||||
// Test MATCH (n {prop: n.prop}) RETURN n
|
||||
// Using `n.prop` needs to work, because filters are run after the value for
|
||||
// matched symbol is obtained.
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto prop = PROPERTY_PAIR("prop");
|
||||
AstTreeStorage storage;
|
||||
auto node_n = NODE("n");
|
||||
@ -997,9 +996,9 @@ TEST(TestSymbolGenerator, WithReturnAll) {
|
||||
|
||||
TEST(TestSymbolGenerator, MatchBfsReturn) {
|
||||
// Test MATCH (n) -[r *bfs..n.prop] (r, n | r.prop)]-> (m) RETURN r AS r
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto prop = dba->Property("prop");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto prop = dba.Property("prop");
|
||||
AstTreeStorage storage;
|
||||
auto *node_n = NODE("n");
|
||||
auto *r_prop = PROPERTY_LOOKUP("r", prop);
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "database/dbms.hpp"
|
||||
#include "query/frontend/semantic/symbol_generator.hpp"
|
||||
#include "query/frontend/semantic/symbol_table.hpp"
|
||||
#include "query/plan/planner.hpp"
|
||||
@ -79,34 +78,34 @@ void CheckPlansProduce(
|
||||
}
|
||||
|
||||
TEST(TestVariableStartPlanner, MatchReturn) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
// Make a graph (v1) -[:r]-> (v2)
|
||||
auto v1 = dba->InsertVertex();
|
||||
auto v2 = dba->InsertVertex();
|
||||
dba->InsertEdge(v1, v2, dba->EdgeType("r"));
|
||||
dba->AdvanceCommand();
|
||||
auto v1 = dba.InsertVertex();
|
||||
auto v2 = dba.InsertVertex();
|
||||
dba.InsertEdge(v1, v2, dba.EdgeType("r"));
|
||||
dba.AdvanceCommand();
|
||||
// Test MATCH (n) -[r]-> (m) RETURN n
|
||||
AstTreeStorage storage;
|
||||
QUERY(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, storage, *dba, [&](const auto &results) {
|
||||
CheckPlansProduce(2, storage, dba, [&](const auto &results) {
|
||||
// We expect to produce only a single (v1) node.
|
||||
AssertRows(results, {{v1}});
|
||||
});
|
||||
}
|
||||
|
||||
TEST(TestVariableStartPlanner, MatchTripletPatternReturn) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
// Make a graph (v1) -[:r]-> (v2) -[:r]-> (v3)
|
||||
auto v1 = dba->InsertVertex();
|
||||
auto v2 = dba->InsertVertex();
|
||||
auto v3 = dba->InsertVertex();
|
||||
dba->InsertEdge(v1, v2, dba->EdgeType("r"));
|
||||
dba->InsertEdge(v2, v3, dba->EdgeType("r"));
|
||||
dba->AdvanceCommand();
|
||||
auto v1 = dba.InsertVertex();
|
||||
auto v2 = dba.InsertVertex();
|
||||
auto v3 = dba.InsertVertex();
|
||||
dba.InsertEdge(v1, v2, dba.EdgeType("r"));
|
||||
dba.InsertEdge(v2, v3, dba.EdgeType("r"));
|
||||
dba.AdvanceCommand();
|
||||
{
|
||||
// Test `MATCH (n) -[r]-> (m) -[e]-> (l) RETURN n`
|
||||
AstTreeStorage storage;
|
||||
@ -114,7 +113,7 @@ 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, storage, *dba, [&](const auto &results) {
|
||||
CheckPlansProduce(3, storage, dba, [&](const auto &results) {
|
||||
// We expect to produce only a single (v1) node.
|
||||
AssertRows(results, {{v1}});
|
||||
});
|
||||
@ -125,22 +124,22 @@ TEST(TestVariableStartPlanner, MatchTripletPatternReturn) {
|
||||
QUERY(MATCH(PATTERN(NODE("n"), EDGE("r", Direction::OUT), NODE("m")),
|
||||
PATTERN(NODE("m"), EDGE("e", Direction::OUT), NODE("l"))),
|
||||
RETURN("n"));
|
||||
CheckPlansProduce(3, storage, *dba, [&](const auto &results) {
|
||||
CheckPlansProduce(3, storage, dba, [&](const auto &results) {
|
||||
AssertRows(results, {{v1}});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TestVariableStartPlanner, MatchOptionalMatchReturn) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
// Make a graph (v1) -[:r]-> (v2) -[:r]-> (v3)
|
||||
auto v1 = dba->InsertVertex();
|
||||
auto v2 = dba->InsertVertex();
|
||||
auto v3 = dba->InsertVertex();
|
||||
dba->InsertEdge(v1, v2, dba->EdgeType("r"));
|
||||
dba->InsertEdge(v2, v3, dba->EdgeType("r"));
|
||||
dba->AdvanceCommand();
|
||||
auto v1 = dba.InsertVertex();
|
||||
auto v2 = dba.InsertVertex();
|
||||
auto v3 = dba.InsertVertex();
|
||||
dba.InsertEdge(v1, v2, dba.EdgeType("r"));
|
||||
dba.InsertEdge(v2, v3, dba.EdgeType("r"));
|
||||
dba.AdvanceCommand();
|
||||
// Test MATCH (n) -[r]-> (m) OPTIONAL MATCH (m) -[e]-> (l) RETURN n, l
|
||||
AstTreeStorage storage;
|
||||
QUERY(
|
||||
@ -149,7 +148,7 @@ 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, storage, *dba, [&](const auto &results) {
|
||||
CheckPlansProduce(4, storage, dba, [&](const auto &results) {
|
||||
// We expect to produce 2 rows:
|
||||
// * (v1), (v3)
|
||||
// * (v2), null
|
||||
@ -158,14 +157,14 @@ TEST(TestVariableStartPlanner, MatchOptionalMatchReturn) {
|
||||
}
|
||||
|
||||
TEST(TestVariableStartPlanner, MatchOptionalMatchMergeReturn) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
// Graph (v1) -[:r]-> (v2)
|
||||
auto v1 = dba->InsertVertex();
|
||||
auto v2 = dba->InsertVertex();
|
||||
auto r_type = dba->EdgeType("r");
|
||||
dba->InsertEdge(v1, v2, r_type);
|
||||
dba->AdvanceCommand();
|
||||
auto v1 = dba.InsertVertex();
|
||||
auto v2 = dba.InsertVertex();
|
||||
auto r_type = dba.EdgeType("r");
|
||||
dba.InsertEdge(v1, v2, r_type);
|
||||
dba.AdvanceCommand();
|
||||
// Test MATCH (n) -[r]-> (m) OPTIONAL MATCH (m) -[e]-> (l)
|
||||
// MERGE (u) -[q:r]-> (v) RETURN n, m, l, u, v
|
||||
AstTreeStorage storage;
|
||||
@ -176,20 +175,20 @@ 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, storage, *dba, [&](const auto &results) {
|
||||
CheckPlansProduce(8, storage, dba, [&](const auto &results) {
|
||||
// We expect to produce a single row: (v1), (v2), null, (v1), (v2)
|
||||
AssertRows(results, {{v1, v2, TypedValue::Null, v1, v2}});
|
||||
});
|
||||
}
|
||||
|
||||
TEST(TestVariableStartPlanner, MatchWithMatchReturn) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
// Graph (v1) -[:r]-> (v2)
|
||||
auto v1 = dba->InsertVertex();
|
||||
auto v2 = dba->InsertVertex();
|
||||
dba->InsertEdge(v1, v2, dba->EdgeType("r"));
|
||||
dba->AdvanceCommand();
|
||||
auto v1 = dba.InsertVertex();
|
||||
auto v2 = dba.InsertVertex();
|
||||
dba.InsertEdge(v1, v2, dba.EdgeType("r"));
|
||||
dba.AdvanceCommand();
|
||||
// Test MATCH (n) -[r]-> (m) WITH n MATCH (m) -[r]-> (l) RETURN n, m, l
|
||||
AstTreeStorage storage;
|
||||
QUERY(MATCH(PATTERN(NODE("n"), EDGE("r", Direction::OUT), NODE("m"))),
|
||||
@ -198,22 +197,22 @@ 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, storage, *dba, [&](const auto &results) {
|
||||
CheckPlansProduce(4, storage, dba, [&](const auto &results) {
|
||||
// We expect to produce a single row: (v1), (v1), (v2)
|
||||
AssertRows(results, {{v1, v1, v2}});
|
||||
});
|
||||
}
|
||||
|
||||
TEST(TestVariableStartPlanner, MatchVariableExpand) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
// Graph (v1) -[:r1]-> (v2) -[:r2]-> (v3)
|
||||
auto v1 = dba->InsertVertex();
|
||||
auto v2 = dba->InsertVertex();
|
||||
auto v3 = dba->InsertVertex();
|
||||
auto r1 = dba->InsertEdge(v1, v2, dba->EdgeType("r1"));
|
||||
auto r2 = dba->InsertEdge(v2, v3, dba->EdgeType("r2"));
|
||||
dba->AdvanceCommand();
|
||||
auto v1 = dba.InsertVertex();
|
||||
auto v2 = dba.InsertVertex();
|
||||
auto v3 = dba.InsertVertex();
|
||||
auto r1 = dba.InsertEdge(v1, v2, dba.EdgeType("r1"));
|
||||
auto r2 = dba.InsertEdge(v2, v3, dba.EdgeType("r2"));
|
||||
dba.AdvanceCommand();
|
||||
// Test MATCH (n) -[r*]-> (m) RETURN r
|
||||
AstTreeStorage storage;
|
||||
auto edge = EDGE_VARIABLE("r", Direction::OUT);
|
||||
@ -222,25 +221,25 @@ TEST(TestVariableStartPlanner, MatchVariableExpand) {
|
||||
TypedValue r1_list(std::vector<TypedValue>{r1}); // [r1]
|
||||
TypedValue r2_list(std::vector<TypedValue>{r2}); // [r2]
|
||||
TypedValue r1_r2_list(std::vector<TypedValue>{r1, r2}); // [r1, r2]
|
||||
CheckPlansProduce(2, storage, *dba, [&](const auto &results) {
|
||||
CheckPlansProduce(2, storage, dba, [&](const auto &results) {
|
||||
AssertRows(results, {{r1_list}, {r2_list}, {r1_r2_list}});
|
||||
});
|
||||
}
|
||||
|
||||
TEST(TestVariableStartPlanner, MatchVariableExpandReferenceNode) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto id = dba->Property("id");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto id = dba.Property("id");
|
||||
// Graph (v1 {id:1}) -[:r1]-> (v2 {id: 2}) -[:r2]-> (v3 {id: 3})
|
||||
auto v1 = dba->InsertVertex();
|
||||
auto v1 = dba.InsertVertex();
|
||||
v1.PropsSet(id, 1);
|
||||
auto v2 = dba->InsertVertex();
|
||||
auto v2 = dba.InsertVertex();
|
||||
v2.PropsSet(id, 2);
|
||||
auto v3 = dba->InsertVertex();
|
||||
auto v3 = dba.InsertVertex();
|
||||
v3.PropsSet(id, 3);
|
||||
auto r1 = dba->InsertEdge(v1, v2, dba->EdgeType("r1"));
|
||||
auto r2 = dba->InsertEdge(v2, v3, dba->EdgeType("r2"));
|
||||
dba->AdvanceCommand();
|
||||
auto r1 = dba.InsertEdge(v1, v2, dba.EdgeType("r1"));
|
||||
auto r2 = dba.InsertEdge(v2, v3, dba.EdgeType("r2"));
|
||||
dba.AdvanceCommand();
|
||||
// Test MATCH (n) -[r*..n.id]-> (m) RETURN r
|
||||
AstTreeStorage storage;
|
||||
auto edge = EDGE_VARIABLE("r", Direction::OUT);
|
||||
@ -249,23 +248,23 @@ TEST(TestVariableStartPlanner, MatchVariableExpandReferenceNode) {
|
||||
// We expect to get a single column with the following rows:
|
||||
TypedValue r1_list(std::vector<TypedValue>{r1}); // [r1] (v1 -[*..1]-> v2)
|
||||
TypedValue r2_list(std::vector<TypedValue>{r2}); // [r2] (v2 -[*..2]-> v3)
|
||||
CheckPlansProduce(2, storage, *dba, [&](const auto &results) {
|
||||
CheckPlansProduce(2, storage, dba, [&](const auto &results) {
|
||||
AssertRows(results, {{r1_list}, {r2_list}});
|
||||
});
|
||||
}
|
||||
|
||||
TEST(TestVariableStartPlanner, MatchVariableExpandBoth) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto id = dba->Property("id");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto id = dba.Property("id");
|
||||
// Graph (v1 {id:1}) -[:r1]-> (v2) -[:r2]-> (v3)
|
||||
auto v1 = dba->InsertVertex();
|
||||
auto v1 = dba.InsertVertex();
|
||||
v1.PropsSet(id, 1);
|
||||
auto v2 = dba->InsertVertex();
|
||||
auto v3 = dba->InsertVertex();
|
||||
auto r1 = dba->InsertEdge(v1, v2, dba->EdgeType("r1"));
|
||||
auto r2 = dba->InsertEdge(v2, v3, dba->EdgeType("r2"));
|
||||
dba->AdvanceCommand();
|
||||
auto v2 = dba.InsertVertex();
|
||||
auto v3 = dba.InsertVertex();
|
||||
auto r1 = dba.InsertEdge(v1, v2, dba.EdgeType("r1"));
|
||||
auto r2 = dba.InsertEdge(v2, v3, dba.EdgeType("r2"));
|
||||
dba.AdvanceCommand();
|
||||
// Test MATCH (n {id:1}) -[r*]- (m) RETURN r
|
||||
AstTreeStorage storage;
|
||||
auto edge = EDGE_VARIABLE("r", Direction::BOTH);
|
||||
@ -275,25 +274,25 @@ TEST(TestVariableStartPlanner, MatchVariableExpandBoth) {
|
||||
// We expect to get a single column with the following rows:
|
||||
TypedValue r1_list(std::vector<TypedValue>{r1}); // [r1]
|
||||
TypedValue r1_r2_list(std::vector<TypedValue>{r1, r2}); // [r1, r2]
|
||||
CheckPlansProduce(2, storage, *dba, [&](const auto &results) {
|
||||
CheckPlansProduce(2, storage, dba, [&](const auto &results) {
|
||||
AssertRows(results, {{r1_list}, {r1_r2_list}});
|
||||
});
|
||||
}
|
||||
|
||||
TEST(TestVariableStartPlanner, MatchBfs) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto id = dba->Property("id");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto id = dba.Property("id");
|
||||
// Graph (v1 {id:1}) -[:r1]-> (v2 {id: 2}) -[:r2]-> (v3 {id: 3})
|
||||
auto v1 = dba->InsertVertex();
|
||||
auto v1 = dba.InsertVertex();
|
||||
v1.PropsSet(id, 1);
|
||||
auto v2 = dba->InsertVertex();
|
||||
auto v2 = dba.InsertVertex();
|
||||
v2.PropsSet(id, 2);
|
||||
auto v3 = dba->InsertVertex();
|
||||
auto v3 = dba.InsertVertex();
|
||||
v3.PropsSet(id, 3);
|
||||
auto r1 = dba->InsertEdge(v1, v2, dba->EdgeType("r1"));
|
||||
dba->InsertEdge(v2, v3, dba->EdgeType("r2"));
|
||||
dba->AdvanceCommand();
|
||||
auto r1 = dba.InsertEdge(v1, v2, dba.EdgeType("r1"));
|
||||
dba.InsertEdge(v2, v3, dba.EdgeType("r2"));
|
||||
dba.AdvanceCommand();
|
||||
// Test MATCH (n) -[r *bfs..10](r, n | n.id <> 3)]-> (m) RETURN r
|
||||
AstTreeStorage storage;
|
||||
auto *bfs = storage.Create<query::EdgeAtom>(
|
||||
@ -306,7 +305,7 @@ TEST(TestVariableStartPlanner, MatchBfs) {
|
||||
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>{r1}); // [r1]
|
||||
CheckPlansProduce(2, storage, *dba, [&](const auto &results) {
|
||||
CheckPlansProduce(2, storage, dba, [&](const auto &results) {
|
||||
AssertRows(results, {{r1_list}});
|
||||
});
|
||||
}
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "database/dbms.hpp"
|
||||
#include "database/graph_db.hpp"
|
||||
#include "database/graph_db_accessor.hpp"
|
||||
|
||||
@ -12,14 +11,14 @@
|
||||
#include "storage/vertex_accessor.hpp"
|
||||
|
||||
TEST(RecordAccessor, Properties) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
|
||||
auto vertex = dba->InsertVertex();
|
||||
auto vertex = dba.InsertVertex();
|
||||
auto &properties = vertex.Properties();
|
||||
|
||||
auto property = dba->Property("PropName");
|
||||
auto property_other = dba->Property("Other");
|
||||
auto property = dba.Property("PropName");
|
||||
auto property_other = dba.Property("Other");
|
||||
EXPECT_EQ(vertex.PropsAt(property).type(), PropertyValue::Type::Null);
|
||||
|
||||
vertex.PropsSet(property, 42);
|
||||
@ -34,43 +33,43 @@ TEST(RecordAccessor, Properties) {
|
||||
}
|
||||
|
||||
TEST(RecordAccessor, DbAccessor) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
|
||||
auto vertex = dba->InsertVertex();
|
||||
auto vertex = dba.InsertVertex();
|
||||
const auto &const_vertex_dba = vertex.db_accessor();
|
||||
EXPECT_EQ(dba.get(), &const_vertex_dba);
|
||||
EXPECT_EQ(&dba, &const_vertex_dba);
|
||||
auto &vertex_dba = vertex.db_accessor();
|
||||
EXPECT_EQ(dba.get(), &vertex_dba);
|
||||
EXPECT_EQ(&dba, &vertex_dba);
|
||||
}
|
||||
|
||||
TEST(RecordAccessor, RecordEquality) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
|
||||
auto v1 = dba->InsertVertex();
|
||||
auto v2 = dba->InsertVertex();
|
||||
auto v1 = dba.InsertVertex();
|
||||
auto v2 = dba.InsertVertex();
|
||||
EXPECT_EQ(v1, v1);
|
||||
EXPECT_NE(v1, v2);
|
||||
|
||||
auto e1 = dba->InsertEdge(v1, v2, dba->EdgeType("type"));
|
||||
auto e2 = dba->InsertEdge(v1, v2, dba->EdgeType("type"));
|
||||
auto e1 = dba.InsertEdge(v1, v2, dba.EdgeType("type"));
|
||||
auto e2 = dba.InsertEdge(v1, v2, dba.EdgeType("type"));
|
||||
EXPECT_EQ(e1, e1);
|
||||
EXPECT_NE(e1, e2);
|
||||
}
|
||||
|
||||
TEST(RecordAccessor, RecordLessThan) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
|
||||
auto v1 = dba->InsertVertex();
|
||||
auto v2 = dba->InsertVertex();
|
||||
auto v1 = dba.InsertVertex();
|
||||
auto v2 = dba.InsertVertex();
|
||||
EXPECT_NE(v1, v2);
|
||||
EXPECT_TRUE(v1 < v2 || v2 < v1);
|
||||
EXPECT_FALSE(v1 < v1);
|
||||
EXPECT_FALSE(v2 < v2);
|
||||
auto e1 = dba->InsertEdge(v1, v2, dba->EdgeType("type"));
|
||||
auto e2 = dba->InsertEdge(v1, v2, dba->EdgeType("type"));
|
||||
auto e1 = dba.InsertEdge(v1, v2, dba.EdgeType("type"));
|
||||
auto e2 = dba.InsertEdge(v1, v2, dba.EdgeType("type"));
|
||||
EXPECT_NE(e1, e2);
|
||||
EXPECT_TRUE(e1 < e2 || e2 < e1);
|
||||
EXPECT_FALSE(e1 < e1);
|
||||
@ -78,30 +77,30 @@ TEST(RecordAccessor, RecordLessThan) {
|
||||
}
|
||||
|
||||
TEST(RecordAccessor, SwitchOldAndSwitchNewMemberFunctionTest) {
|
||||
Dbms dbms;
|
||||
GraphDb db;
|
||||
|
||||
// test both Switches work on new record
|
||||
{
|
||||
auto dba = dbms.active();
|
||||
auto v1 = dba->InsertVertex();
|
||||
GraphDbAccessor dba(db);
|
||||
auto v1 = dba.InsertVertex();
|
||||
v1.SwitchOld();
|
||||
v1.SwitchNew();
|
||||
dba->Commit();
|
||||
dba.Commit();
|
||||
}
|
||||
|
||||
// test both Switches work on existing record
|
||||
{
|
||||
auto dba = dbms.active();
|
||||
auto v1 = *dba->Vertices(false).begin();
|
||||
GraphDbAccessor dba(db);
|
||||
auto v1 = *dba.Vertices(false).begin();
|
||||
v1.SwitchOld();
|
||||
v1.SwitchNew();
|
||||
}
|
||||
|
||||
// ensure switch exposes the right data
|
||||
{
|
||||
auto dba = dbms.active();
|
||||
auto label = dba->Label("label");
|
||||
auto v1 = *dba->Vertices(false).begin();
|
||||
GraphDbAccessor dba(db);
|
||||
auto label = dba.Label("label");
|
||||
auto v1 = *dba.Vertices(false).begin();
|
||||
|
||||
EXPECT_FALSE(v1.has_label(label)); // old record
|
||||
v1.add_label(label); // modifying data does not switch to new
|
||||
@ -114,27 +113,27 @@ TEST(RecordAccessor, SwitchOldAndSwitchNewMemberFunctionTest) {
|
||||
}
|
||||
|
||||
TEST(RecordAccessor, Reconstruct) {
|
||||
Dbms dbms;
|
||||
auto label = dbms.active()->Label("label");
|
||||
GraphDb db;
|
||||
auto label = GraphDbAccessor(db).Label("label");
|
||||
|
||||
{
|
||||
// we must operate on an old vertex
|
||||
// because otherwise we only have new
|
||||
// so create a vertex and commit it
|
||||
auto dba = dbms.active();
|
||||
dba->InsertVertex();
|
||||
dba->Commit();
|
||||
GraphDbAccessor dba(db);
|
||||
dba.InsertVertex();
|
||||
dba.Commit();
|
||||
}
|
||||
|
||||
// ensure we don't have label set
|
||||
auto dba = dbms.active();
|
||||
auto v1 = *dba->Vertices(false).begin();
|
||||
GraphDbAccessor dba(db);
|
||||
auto v1 = *dba.Vertices(false).begin();
|
||||
v1.SwitchNew();
|
||||
EXPECT_FALSE(v1.has_label(label));
|
||||
|
||||
{
|
||||
// update the record through a different accessor
|
||||
auto v1_other_accessor = *dba->Vertices(false).begin();
|
||||
auto v1_other_accessor = *dba.Vertices(false).begin();
|
||||
v1_other_accessor.add_label(label);
|
||||
EXPECT_FALSE(v1.has_label(label));
|
||||
v1_other_accessor.SwitchNew();
|
||||
@ -148,15 +147,15 @@ TEST(RecordAccessor, Reconstruct) {
|
||||
}
|
||||
|
||||
TEST(RecordAccessor, VertexLabels) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto v1 = dba->InsertVertex();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto v1 = dba.InsertVertex();
|
||||
auto &labels = v1.labels();
|
||||
|
||||
EXPECT_EQ(v1.labels().size(), 0);
|
||||
|
||||
GraphDbTypes::Label l1 = dba->Label("label1");
|
||||
GraphDbTypes::Label l2 = dba->Label("label2");
|
||||
GraphDbTypes::Label l1 = dba.Label("label1");
|
||||
GraphDbTypes::Label l2 = dba.Label("label2");
|
||||
|
||||
// adding labels
|
||||
EXPECT_FALSE(v1.has_label(l1));
|
||||
@ -176,7 +175,7 @@ TEST(RecordAccessor, VertexLabels) {
|
||||
EXPECT_EQ(labels.size(), 2);
|
||||
|
||||
// removing labels
|
||||
GraphDbTypes::Label l3 = dba->Label("label3");
|
||||
GraphDbTypes::Label l3 = dba.Label("label3");
|
||||
EXPECT_EQ(v1.remove_label(l3), 0);
|
||||
EXPECT_EQ(labels.size(), 2);
|
||||
|
||||
@ -189,39 +188,39 @@ TEST(RecordAccessor, VertexLabels) {
|
||||
}
|
||||
|
||||
TEST(RecordAccessor, EdgeType) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto v1 = dba->InsertVertex();
|
||||
auto v2 = dba->InsertVertex();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto v1 = dba.InsertVertex();
|
||||
auto v2 = dba.InsertVertex();
|
||||
|
||||
GraphDbTypes::EdgeType likes = dba->EdgeType("likes");
|
||||
GraphDbTypes::EdgeType hates = dba->EdgeType("hates");
|
||||
GraphDbTypes::EdgeType likes = dba.EdgeType("likes");
|
||||
GraphDbTypes::EdgeType hates = dba.EdgeType("hates");
|
||||
|
||||
auto edge = dba->InsertEdge(v1, v2, likes);
|
||||
auto edge = dba.InsertEdge(v1, v2, likes);
|
||||
EXPECT_EQ(edge.EdgeType(), likes);
|
||||
EXPECT_NE(edge.EdgeType(), hates);
|
||||
}
|
||||
|
||||
TEST(RecordAccessor, EdgeIsCycle) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto v1 = dba->InsertVertex();
|
||||
auto v2 = dba->InsertVertex();
|
||||
auto likes = dba->EdgeType("edge_type");
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto v1 = dba.InsertVertex();
|
||||
auto v2 = dba.InsertVertex();
|
||||
auto likes = dba.EdgeType("edge_type");
|
||||
|
||||
EXPECT_TRUE(dba->InsertEdge(v1, v1, likes).is_cycle());
|
||||
EXPECT_TRUE(dba->InsertEdge(v2, v2, likes).is_cycle());
|
||||
EXPECT_FALSE(dba->InsertEdge(v1, v2, likes).is_cycle());
|
||||
EXPECT_FALSE(dba->InsertEdge(v2, v1, likes).is_cycle());
|
||||
EXPECT_TRUE(dba.InsertEdge(v1, v1, likes).is_cycle());
|
||||
EXPECT_TRUE(dba.InsertEdge(v2, v2, likes).is_cycle());
|
||||
EXPECT_FALSE(dba.InsertEdge(v1, v2, likes).is_cycle());
|
||||
EXPECT_FALSE(dba.InsertEdge(v2, v1, likes).is_cycle());
|
||||
}
|
||||
|
||||
TEST(RecordAccessor, VertexEdgeConnections) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto v1 = dba->InsertVertex();
|
||||
auto v2 = dba->InsertVertex();
|
||||
auto edge = dba->InsertEdge(v1, v2, dba->EdgeType("likes"));
|
||||
dba->AdvanceCommand();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto v1 = dba.InsertVertex();
|
||||
auto v2 = dba.InsertVertex();
|
||||
auto edge = dba.InsertEdge(v1, v2, dba.EdgeType("likes"));
|
||||
dba.AdvanceCommand();
|
||||
|
||||
EXPECT_EQ(edge.from(), v1);
|
||||
EXPECT_NE(edge.from(), v2);
|
||||
@ -248,18 +247,18 @@ TEST(RecordAccessor, VertexEdgeConnections) {
|
||||
}
|
||||
|
||||
TEST(RecordAccessor, VertexEdgeConnectionsWithExistingVertex) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto v1 = dba->InsertVertex();
|
||||
auto v2 = dba->InsertVertex();
|
||||
auto v3 = dba->InsertVertex();
|
||||
auto edge_type = dba->EdgeType("edge type");
|
||||
auto e12 = dba->InsertEdge(v1, v2, edge_type);
|
||||
auto e22 = dba->InsertEdge(v2, v2, edge_type);
|
||||
auto e23a = dba->InsertEdge(v2, v3, edge_type);
|
||||
auto e23b = dba->InsertEdge(v2, v3, edge_type);
|
||||
auto e32 = dba->InsertEdge(v3, v2, edge_type);
|
||||
dba->AdvanceCommand();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto v1 = dba.InsertVertex();
|
||||
auto v2 = dba.InsertVertex();
|
||||
auto v3 = dba.InsertVertex();
|
||||
auto edge_type = dba.EdgeType("edge type");
|
||||
auto e12 = dba.InsertEdge(v1, v2, edge_type);
|
||||
auto e22 = dba.InsertEdge(v2, v2, edge_type);
|
||||
auto e23a = dba.InsertEdge(v2, v3, edge_type);
|
||||
auto e23b = dba.InsertEdge(v2, v3, edge_type);
|
||||
auto e32 = dba.InsertEdge(v3, v2, edge_type);
|
||||
dba.AdvanceCommand();
|
||||
|
||||
TEST_EDGE_ITERABLE(v1.out(v1));
|
||||
TEST_EDGE_ITERABLE(v1.out(v2), {e12});
|
||||
@ -283,18 +282,18 @@ TEST(RecordAccessor, VertexEdgeConnectionsWithExistingVertex) {
|
||||
}
|
||||
|
||||
TEST(RecordAccessor, VertexEdgeConnectionsWithEdgeType) {
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
auto v1 = dba->InsertVertex();
|
||||
auto v2 = dba->InsertVertex();
|
||||
auto a = dba->EdgeType("a");
|
||||
auto b = dba->EdgeType("b");
|
||||
auto c = dba->EdgeType("c");
|
||||
auto ea = dba->InsertEdge(v1, v2, a);
|
||||
auto eb_1 = dba->InsertEdge(v2, v1, b);
|
||||
auto eb_2 = dba->InsertEdge(v2, v1, b);
|
||||
auto ec = dba->InsertEdge(v1, v2, c);
|
||||
dba->AdvanceCommand();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
auto v1 = dba.InsertVertex();
|
||||
auto v2 = dba.InsertVertex();
|
||||
auto a = dba.EdgeType("a");
|
||||
auto b = dba.EdgeType("b");
|
||||
auto c = dba.EdgeType("c");
|
||||
auto ea = dba.InsertEdge(v1, v2, a);
|
||||
auto eb_1 = dba.InsertEdge(v2, v1, b);
|
||||
auto eb_2 = dba.InsertEdge(v2, v1, b);
|
||||
auto ec = dba.InsertEdge(v1, v2, c);
|
||||
dba.AdvanceCommand();
|
||||
|
||||
TEST_EDGE_ITERABLE(v1.in(), {eb_1, eb_2});
|
||||
TEST_EDGE_ITERABLE(v2.in(), {ea, ec});
|
||||
|
@ -6,7 +6,6 @@
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "communication/bolt/v1/decoder/decoder.hpp"
|
||||
#include "database/dbms.hpp"
|
||||
#include "durability/hashed_file_reader.hpp"
|
||||
#include "durability/recovery.hpp"
|
||||
#include "durability/version.hpp"
|
||||
@ -16,9 +15,7 @@ DECLARE_int32(snapshot_cycle_sec);
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
char tmp[] = "XXXXXX";
|
||||
const fs::path SNAPSHOTS_RECOVERY_ALL_DB_DIR = mkdtemp(tmp);
|
||||
const fs::path SNAPSHOTS_RECOVERY_DEFAULT_DB_DIR =
|
||||
SNAPSHOTS_RECOVERY_ALL_DB_DIR / "default";
|
||||
const fs::path SNAPSHOTS_DIR = mkdtemp(tmp);
|
||||
|
||||
std::vector<fs::path> GetFilesFromDir(
|
||||
const std::string &snapshots_default_db_dir) {
|
||||
@ -29,9 +26,8 @@ std::vector<fs::path> GetFilesFromDir(
|
||||
}
|
||||
|
||||
void CleanDbDir() {
|
||||
if (!fs::exists(SNAPSHOTS_RECOVERY_DEFAULT_DB_DIR)) return;
|
||||
std::vector<fs::path> files =
|
||||
GetFilesFromDir(SNAPSHOTS_RECOVERY_DEFAULT_DB_DIR);
|
||||
if (!fs::exists(SNAPSHOTS_DIR)) return;
|
||||
std::vector<fs::path> files = GetFilesFromDir(SNAPSHOTS_DIR);
|
||||
for (auto file : files) {
|
||||
fs::remove(file);
|
||||
}
|
||||
@ -48,47 +44,45 @@ class RecoveryTest : public ::testing::Test {
|
||||
const int snapshot_max_retained_ = 10;
|
||||
};
|
||||
|
||||
void CreateSmallGraph(Dbms &dbms) {
|
||||
auto dba = dbms.active();
|
||||
void CreateSmallGraph(GraphDb &db) {
|
||||
GraphDbAccessor dba(db);
|
||||
|
||||
// setup (v1) - [:likes] -> (v2) <- [:hates] - (v3)
|
||||
auto va1 = dba->InsertVertex();
|
||||
auto va2 = dba->InsertVertex();
|
||||
dba->InsertEdge(va1, va2, dba->EdgeType("likes"));
|
||||
auto va3 = dba->InsertVertex();
|
||||
dba->InsertEdge(va3, va2, dba->EdgeType("hates"));
|
||||
dba->Commit();
|
||||
auto va1 = dba.InsertVertex();
|
||||
auto va2 = dba.InsertVertex();
|
||||
dba.InsertEdge(va1, va2, dba.EdgeType("likes"));
|
||||
auto va3 = dba.InsertVertex();
|
||||
dba.InsertEdge(va3, va2, dba.EdgeType("hates"));
|
||||
dba.Commit();
|
||||
}
|
||||
|
||||
void CreateBigGraph(Dbms &dbms) {
|
||||
void CreateBigGraph(GraphDb &db) {
|
||||
// creates graph with one inner vertex connected with other 999 outer vertices
|
||||
// relationships are directed from outer vertices to the inner vertex
|
||||
// every vertex hash label "label" and property "prop" with value "prop"
|
||||
// every relationship has type "type" and property "prop" with value "prop"
|
||||
auto dba = dbms.active();
|
||||
auto va_middle = dba->InsertVertex();
|
||||
va_middle.add_label(dba->Label("label"));
|
||||
va_middle.PropsSet(dba->Property("prop"), "prop");
|
||||
GraphDbAccessor dba(db);
|
||||
auto va_middle = dba.InsertVertex();
|
||||
va_middle.add_label(dba.Label("label"));
|
||||
va_middle.PropsSet(dba.Property("prop"), "prop");
|
||||
for (int i = 1; i < 1000; ++i) {
|
||||
auto va = dba->InsertVertex();
|
||||
va.add_label(dba->Label("label"));
|
||||
va.PropsSet(dba->Property("prop"), "prop");
|
||||
auto ea = dba->InsertEdge(va, va_middle, dba->EdgeType("type"));
|
||||
ea.PropsSet(dba->Property("prop"), "prop");
|
||||
auto va = dba.InsertVertex();
|
||||
va.add_label(dba.Label("label"));
|
||||
va.PropsSet(dba.Property("prop"), "prop");
|
||||
auto ea = dba.InsertEdge(va, va_middle, dba.EdgeType("type"));
|
||||
ea.PropsSet(dba.Property("prop"), "prop");
|
||||
}
|
||||
dba->Commit();
|
||||
dba.Commit();
|
||||
}
|
||||
|
||||
void TakeSnapshot(Dbms &dbms, int snapshot_max_retained_) {
|
||||
auto dba = dbms.active();
|
||||
void TakeSnapshot(GraphDb &db, int snapshot_max_retained_) {
|
||||
GraphDbAccessor dba(db);
|
||||
Snapshooter snapshooter;
|
||||
snapshooter.MakeSnapshot(*dba.get(), SNAPSHOTS_RECOVERY_DEFAULT_DB_DIR,
|
||||
snapshot_max_retained_);
|
||||
snapshooter.MakeSnapshot(dba, SNAPSHOTS_DIR, snapshot_max_retained_);
|
||||
}
|
||||
|
||||
std::string GetLatestSnapshot() {
|
||||
std::vector<fs::path> files =
|
||||
GetFilesFromDir(SNAPSHOTS_RECOVERY_DEFAULT_DB_DIR);
|
||||
std::vector<fs::path> files = GetFilesFromDir(SNAPSHOTS_DIR);
|
||||
CHECK(static_cast<int>(files.size()) == 1) << "No snapshot files in folder.";
|
||||
std::sort(files.rbegin(), files.rend());
|
||||
return files[0];
|
||||
@ -98,9 +92,9 @@ TEST_F(RecoveryTest, TestEncoding) {
|
||||
// Creates snapshot of the small graph. Uses file_reader_buffer and bolt
|
||||
// decoder to read data from the snapshot and reads graph from it. After
|
||||
// reading graph is tested.
|
||||
Dbms dbms;
|
||||
CreateSmallGraph(dbms);
|
||||
TakeSnapshot(dbms, snapshot_max_retained_);
|
||||
GraphDb db;
|
||||
CreateSmallGraph(db);
|
||||
TakeSnapshot(db, snapshot_max_retained_);
|
||||
std::string snapshot = GetLatestSnapshot();
|
||||
|
||||
HashedFileReader buffer;
|
||||
@ -165,31 +159,31 @@ TEST_F(RecoveryTest, TestEncoding) {
|
||||
TEST_F(RecoveryTest, TestEncodingAndDecoding) {
|
||||
// Creates snapshot of the small graph. Uses Recovery to recover graph from
|
||||
// the snapshot file. After creation graph is tested.
|
||||
Dbms dbms;
|
||||
CreateSmallGraph(dbms);
|
||||
TakeSnapshot(dbms, snapshot_max_retained_);
|
||||
GraphDb db;
|
||||
CreateSmallGraph(db);
|
||||
TakeSnapshot(db, snapshot_max_retained_);
|
||||
std::string snapshot = GetLatestSnapshot();
|
||||
|
||||
// New dbms is needed - old dbms has database "default"
|
||||
Dbms dbms_recover;
|
||||
auto dba_recover = dbms_recover.active();
|
||||
// New db is needed - old db has database "default"
|
||||
GraphDb db_recover;
|
||||
GraphDbAccessor dba_recover(db_recover);
|
||||
|
||||
Recovery recovery;
|
||||
ASSERT_TRUE(recovery.Recover(snapshot, *dba_recover));
|
||||
ASSERT_TRUE(recovery.Recover(snapshot, dba_recover));
|
||||
|
||||
std::vector<VertexAccessor> vertices;
|
||||
std::vector<EdgeAccessor> edges;
|
||||
|
||||
auto dba = dbms_recover.active();
|
||||
GraphDbAccessor dba(db_recover);
|
||||
int64_t vertex_count = 0;
|
||||
for (const auto &vertex : dba->Vertices(false)) {
|
||||
for (const auto &vertex : dba.Vertices(false)) {
|
||||
vertices.push_back(vertex);
|
||||
vertex_count++;
|
||||
}
|
||||
EXPECT_EQ(vertex_count, 3);
|
||||
|
||||
int64_t edge_count = 0;
|
||||
for (const auto &edge : dba->Edges(false)) {
|
||||
for (const auto &edge : dba.Edges(false)) {
|
||||
EXPECT_NE(vertices.end(),
|
||||
std::find(vertices.begin(), vertices.end(), edge.to()));
|
||||
EXPECT_NE(vertices.end(),
|
||||
@ -207,25 +201,25 @@ TEST_F(RecoveryTest, TestEncodingAndDecoding) {
|
||||
TEST_F(RecoveryTest, TestEncodingAndRecovering) {
|
||||
// Creates snapshot of the big graph. Uses Recovery to recover graph from
|
||||
// the snapshot file. After creation graph is tested.
|
||||
Dbms dbms;
|
||||
CreateBigGraph(dbms);
|
||||
TakeSnapshot(dbms, snapshot_max_retained_);
|
||||
GraphDb db;
|
||||
CreateBigGraph(db);
|
||||
TakeSnapshot(db, snapshot_max_retained_);
|
||||
std::string snapshot = GetLatestSnapshot();
|
||||
|
||||
// New dbms is needed - old dbms has database "default"
|
||||
Dbms dbms_recover;
|
||||
auto dba_recover = dbms_recover.active();
|
||||
// New db is needed - old db has database "default"
|
||||
GraphDb db_recover;
|
||||
GraphDbAccessor dba_recover(db_recover);
|
||||
|
||||
Recovery recovery;
|
||||
EXPECT_TRUE(recovery.Recover(snapshot, *dba_recover));
|
||||
EXPECT_TRUE(recovery.Recover(snapshot, dba_recover));
|
||||
|
||||
auto dba_get = dbms_recover.active();
|
||||
GraphDbAccessor dba_get(db_recover);
|
||||
int64_t vertex_count = 0;
|
||||
for (const auto &vertex : dba_get->Vertices(false)) {
|
||||
for (const auto &vertex : dba_get.Vertices(false)) {
|
||||
EXPECT_EQ(vertex.labels().size(), 1);
|
||||
EXPECT_TRUE(vertex.has_label(dba_get->Label("label")));
|
||||
EXPECT_TRUE(vertex.has_label(dba_get.Label("label")));
|
||||
query::TypedValue prop =
|
||||
query::TypedValue(vertex.PropsAt(dba_get->Property("prop")));
|
||||
query::TypedValue(vertex.PropsAt(dba_get.Property("prop")));
|
||||
query::TypedValue expected_prop = query::TypedValue(PropertyValue("prop"));
|
||||
EXPECT_TRUE((prop == expected_prop).Value<bool>());
|
||||
vertex_count++;
|
||||
@ -233,45 +227,45 @@ TEST_F(RecoveryTest, TestEncodingAndRecovering) {
|
||||
EXPECT_EQ(vertex_count, 1000);
|
||||
|
||||
int64_t edge_count = 0;
|
||||
for (const auto &edge : dba_get->Edges(false)) {
|
||||
EXPECT_EQ(edge.EdgeType(), dba_get->EdgeType("type"));
|
||||
for (const auto &edge : dba_get.Edges(false)) {
|
||||
EXPECT_EQ(edge.EdgeType(), dba_get.EdgeType("type"));
|
||||
query::TypedValue prop =
|
||||
query::TypedValue(edge.PropsAt(dba_get->Property("prop")));
|
||||
query::TypedValue(edge.PropsAt(dba_get.Property("prop")));
|
||||
query::TypedValue expected_prop = query::TypedValue(PropertyValue("prop"));
|
||||
EXPECT_TRUE((prop == expected_prop).Value<bool>());
|
||||
edge_count++;
|
||||
}
|
||||
EXPECT_EQ(edge_count, 999);
|
||||
dba_get->Commit();
|
||||
dba_get.Commit();
|
||||
}
|
||||
|
||||
TEST_F(RecoveryTest, TestLabelPropertyIndexRecovery) {
|
||||
// Creates snapshot of the graph with indices.
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
dba->BuildIndex(dba->Label("label"), dba->Property("prop"));
|
||||
dba->Commit();
|
||||
CreateBigGraph(dbms);
|
||||
TakeSnapshot(dbms, snapshot_max_retained_);
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
dba.BuildIndex(dba.Label("label"), dba.Property("prop"));
|
||||
dba.Commit();
|
||||
CreateBigGraph(db);
|
||||
TakeSnapshot(db, snapshot_max_retained_);
|
||||
std::string snapshot = GetLatestSnapshot();
|
||||
|
||||
Dbms dbms_recover;
|
||||
auto dba_recover = dbms_recover.active();
|
||||
GraphDb db_recover;
|
||||
GraphDbAccessor dba_recover(db_recover);
|
||||
|
||||
Recovery recovery;
|
||||
EXPECT_TRUE(recovery.Recover(snapshot, *dba_recover));
|
||||
EXPECT_TRUE(recovery.Recover(snapshot, dba_recover));
|
||||
|
||||
auto dba_get = dbms_recover.active();
|
||||
EXPECT_EQ(dba_get->GetIndicesKeys().size(), 1);
|
||||
EXPECT_TRUE(dba_get->LabelPropertyIndexExists(dba_get->Label("label"),
|
||||
dba_get->Property("prop")));
|
||||
GraphDbAccessor dba_get(db_recover);
|
||||
EXPECT_EQ(dba_get.GetIndicesKeys().size(), 1);
|
||||
EXPECT_TRUE(dba_get.LabelPropertyIndexExists(dba_get.Label("label"),
|
||||
dba_get.Property("prop")));
|
||||
|
||||
int64_t vertex_count = 0;
|
||||
for (const auto &vertex : dba_get->Vertices(false)) {
|
||||
for (const auto &vertex : dba_get.Vertices(false)) {
|
||||
EXPECT_EQ(vertex.labels().size(), 1);
|
||||
EXPECT_TRUE(vertex.has_label(dba_get->Label("label")));
|
||||
EXPECT_TRUE(vertex.has_label(dba_get.Label("label")));
|
||||
query::TypedValue prop =
|
||||
query::TypedValue(vertex.PropsAt(dba_get->Property("prop")));
|
||||
query::TypedValue(vertex.PropsAt(dba_get.Property("prop")));
|
||||
query::TypedValue expected_prop = query::TypedValue(PropertyValue("prop"));
|
||||
EXPECT_TRUE((prop == expected_prop).Value<bool>());
|
||||
vertex_count++;
|
||||
@ -279,16 +273,16 @@ TEST_F(RecoveryTest, TestLabelPropertyIndexRecovery) {
|
||||
EXPECT_EQ(vertex_count, 1000);
|
||||
|
||||
int64_t edge_count = 0;
|
||||
for (const auto &edge : dba_get->Edges(false)) {
|
||||
EXPECT_EQ(edge.EdgeType(), dba_get->EdgeType("type"));
|
||||
for (const auto &edge : dba_get.Edges(false)) {
|
||||
EXPECT_EQ(edge.EdgeType(), dba_get.EdgeType("type"));
|
||||
query::TypedValue prop =
|
||||
query::TypedValue(edge.PropsAt(dba_get->Property("prop")));
|
||||
query::TypedValue(edge.PropsAt(dba_get.Property("prop")));
|
||||
query::TypedValue expected_prop = query::TypedValue(PropertyValue("prop"));
|
||||
EXPECT_TRUE((prop == expected_prop).Value<bool>());
|
||||
edge_count++;
|
||||
}
|
||||
EXPECT_EQ(edge_count, 999);
|
||||
dba_get->Commit();
|
||||
dba_get.Commit();
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
@ -3,7 +3,8 @@
|
||||
#include "gflags/gflags.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "database/dbms.hpp"
|
||||
#include "database/graph_db.hpp"
|
||||
#include "database/graph_db_accessor.hpp"
|
||||
#include "durability/snapshooter.hpp"
|
||||
|
||||
DECLARE_bool(snapshot_on_exit);
|
||||
@ -13,9 +14,7 @@ DECLARE_string(snapshot_directory);
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
char tmp[] = "XXXXXX";
|
||||
const fs::path SNAPSHOTS_FOLDER_ALL_DB = mkdtemp(tmp);
|
||||
const fs::path SNAPSHOTS_TEST_DEFAULT_DB_DIR =
|
||||
SNAPSHOTS_FOLDER_ALL_DB / "default";
|
||||
const fs::path SNAPSHOTS_DIR = mkdtemp(tmp);
|
||||
|
||||
// Other functionality is tested in recovery tests.
|
||||
|
||||
@ -28,8 +27,8 @@ std::vector<fs::path> GetFilesFromDir(
|
||||
}
|
||||
|
||||
void CleanDbDir() {
|
||||
if (!fs::exists(SNAPSHOTS_TEST_DEFAULT_DB_DIR)) return;
|
||||
std::vector<fs::path> files = GetFilesFromDir(SNAPSHOTS_TEST_DEFAULT_DB_DIR);
|
||||
if (!fs::exists(SNAPSHOTS_DIR)) return;
|
||||
std::vector<fs::path> files = GetFilesFromDir(SNAPSHOTS_DIR);
|
||||
for (auto file : files) {
|
||||
fs::remove(file);
|
||||
}
|
||||
@ -48,66 +47,66 @@ class SnapshotTest : public ::testing::Test {
|
||||
|
||||
TEST_F(SnapshotTest, CreateLessThanMaxRetainedSnapshotsTests) {
|
||||
const int snapshot_max_retained = 10;
|
||||
Dbms dbms;
|
||||
GraphDb db;
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
auto dba = dbms.active();
|
||||
GraphDbAccessor dba(db);
|
||||
Snapshooter snapshooter;
|
||||
snapshooter.MakeSnapshot(*dba.get(), SNAPSHOTS_TEST_DEFAULT_DB_DIR,
|
||||
snapshooter.MakeSnapshot(dba, SNAPSHOTS_DIR,
|
||||
snapshot_max_retained);
|
||||
}
|
||||
|
||||
std::vector<fs::path> files = GetFilesFromDir(SNAPSHOTS_TEST_DEFAULT_DB_DIR);
|
||||
std::vector<fs::path> files = GetFilesFromDir(SNAPSHOTS_DIR);
|
||||
EXPECT_EQ(files.size(), 3);
|
||||
}
|
||||
|
||||
TEST_F(SnapshotTest, CreateMoreThanMaxRetainedSnapshotsTests) {
|
||||
const int snapshot_max_retained = 2;
|
||||
Dbms dbms;
|
||||
GraphDb db;
|
||||
|
||||
fs::path first_snapshot;
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
auto dba = dbms.active();
|
||||
GraphDbAccessor dba(db);
|
||||
Snapshooter snapshooter;
|
||||
snapshooter.MakeSnapshot(*dba.get(), SNAPSHOTS_TEST_DEFAULT_DB_DIR,
|
||||
snapshooter.MakeSnapshot(dba, SNAPSHOTS_DIR,
|
||||
snapshot_max_retained);
|
||||
if (i == 0) {
|
||||
std::vector<fs::path> files_begin =
|
||||
GetFilesFromDir(SNAPSHOTS_TEST_DEFAULT_DB_DIR);
|
||||
GetFilesFromDir(SNAPSHOTS_DIR);
|
||||
EXPECT_EQ(files_begin.size(), 1);
|
||||
first_snapshot = files_begin[0];
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<fs::path> files_end =
|
||||
GetFilesFromDir(SNAPSHOTS_TEST_DEFAULT_DB_DIR);
|
||||
GetFilesFromDir(SNAPSHOTS_DIR);
|
||||
EXPECT_EQ(files_end.size(), 2);
|
||||
EXPECT_EQ(fs::exists(first_snapshot), false);
|
||||
}
|
||||
|
||||
TEST_F(SnapshotTest, CreateSnapshotWithUnlimitedMaxRetainedSnapshots) {
|
||||
const int snapshot_max_retained = -1;
|
||||
Dbms dbms;
|
||||
GraphDb db;
|
||||
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
auto dba = dbms.active();
|
||||
GraphDbAccessor dba(db);
|
||||
Snapshooter snapshooter;
|
||||
snapshooter.MakeSnapshot(*dba.get(), SNAPSHOTS_TEST_DEFAULT_DB_DIR,
|
||||
snapshooter.MakeSnapshot(dba, SNAPSHOTS_DIR,
|
||||
snapshot_max_retained);
|
||||
}
|
||||
|
||||
std::vector<fs::path> files = GetFilesFromDir(SNAPSHOTS_TEST_DEFAULT_DB_DIR);
|
||||
std::vector<fs::path> files = GetFilesFromDir(SNAPSHOTS_DIR);
|
||||
EXPECT_EQ(files.size(), 10);
|
||||
}
|
||||
|
||||
TEST_F(SnapshotTest, TestSnapshotFileOnDbDestruct) {
|
||||
{
|
||||
FLAGS_snapshot_directory = SNAPSHOTS_FOLDER_ALL_DB;
|
||||
FLAGS_snapshot_directory = SNAPSHOTS_DIR;
|
||||
FLAGS_snapshot_on_exit = true;
|
||||
Dbms dbms;
|
||||
auto dba = dbms.active();
|
||||
GraphDb db;
|
||||
GraphDbAccessor dba(db);
|
||||
}
|
||||
std::vector<fs::path> files = GetFilesFromDir(SNAPSHOTS_TEST_DEFAULT_DB_DIR);
|
||||
std::vector<fs::path> files = GetFilesFromDir(SNAPSHOTS_DIR);
|
||||
// snapshot is created on dbms destruction
|
||||
EXPECT_EQ(files.size(), 1);
|
||||
}
|
||||
|
@ -7,8 +7,9 @@
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#include "database/dbms.hpp"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "database/graph_db_accessor.hpp"
|
||||
#include "query/typed_value.hpp"
|
||||
|
||||
using query::TypedValue;
|
||||
@ -17,8 +18,8 @@ using query::TypedValueException;
|
||||
class AllTypesFixture : public testing::Test {
|
||||
protected:
|
||||
std::vector<TypedValue> values_;
|
||||
Dbms dbms_;
|
||||
std::unique_ptr<GraphDbAccessor> dba_ = dbms_.active();
|
||||
GraphDb db_;
|
||||
GraphDbAccessor dba_{db_};
|
||||
|
||||
void SetUp() override {
|
||||
values_.emplace_back(TypedValue::Null);
|
||||
@ -34,11 +35,10 @@ class AllTypesFixture : public testing::Test {
|
||||
{"c", 42},
|
||||
{"d", 0.5},
|
||||
{"e", TypedValue::Null}});
|
||||
auto vertex = dba_->InsertVertex();
|
||||
auto vertex = dba_.InsertVertex();
|
||||
values_.emplace_back(vertex);
|
||||
values_.emplace_back(
|
||||
dba_->InsertEdge(vertex, vertex, dba_->EdgeType("et")));
|
||||
values_.emplace_back(query::Path(dba_->InsertVertex()));
|
||||
values_.emplace_back(dba_.InsertEdge(vertex, vertex, dba_.EdgeType("et")));
|
||||
values_.emplace_back(query::Path(dba_.InsertVertex()));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -4,7 +4,6 @@ add_executable(mg_recovery_check
|
||||
mg_recovery_check.cpp
|
||||
${memgraph_src_dir}/communication/bolt/v1/decoder/decoded_value.cpp
|
||||
${memgraph_src_dir}/data_structures/concurrent/skiplist_gc.cpp
|
||||
${memgraph_src_dir}/database/dbms.cpp
|
||||
${memgraph_src_dir}/database/graph_db.cpp
|
||||
${memgraph_src_dir}/database/graph_db_accessor.cpp
|
||||
${memgraph_src_dir}/durability/recovery.cpp
|
||||
|
@ -3,7 +3,8 @@
|
||||
#include "gflags/gflags.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "database/dbms.hpp"
|
||||
#include "database/graph_db.hpp"
|
||||
#include "durability/recovery.hpp"
|
||||
#include "query/typed_value.hpp"
|
||||
|
||||
static const char *usage =
|
||||
@ -19,28 +20,29 @@ class RecoveryTest : public ::testing::Test {
|
||||
void SetUp() override {
|
||||
Recovery recovery;
|
||||
std::string snapshot(FLAGS_snapshot_dir + "/snapshot");
|
||||
recovery.Recover(snapshot, *dbms_.active());
|
||||
GraphDbAccessor dba(db_);
|
||||
recovery.Recover(snapshot, dba);
|
||||
}
|
||||
|
||||
Dbms dbms_;
|
||||
GraphDb db_;
|
||||
};
|
||||
|
||||
TEST_F(RecoveryTest, TestVerticesRecovered) {
|
||||
auto dba = dbms_.active();
|
||||
EXPECT_EQ(dba->VerticesCount(), 10);
|
||||
EXPECT_EQ(dba->VerticesCount(dba->Label("Comment")), 5);
|
||||
for (const auto &vertex : dba->Vertices(dba->Label("Comment"), false)) {
|
||||
EXPECT_TRUE(vertex.has_label(dba->Label("Message")));
|
||||
GraphDbAccessor dba(db_);
|
||||
EXPECT_EQ(dba.VerticesCount(), 10);
|
||||
EXPECT_EQ(dba.VerticesCount(dba.Label("Comment")), 5);
|
||||
for (const auto &vertex : dba.Vertices(dba.Label("Comment"), false)) {
|
||||
EXPECT_TRUE(vertex.has_label(dba.Label("Message")));
|
||||
}
|
||||
EXPECT_EQ(dba->VerticesCount(dba->Label("Forum")), 5);
|
||||
EXPECT_EQ(dba.VerticesCount(dba.Label("Forum")), 5);
|
||||
}
|
||||
|
||||
TEST_F(RecoveryTest, TestPropertyNull) {
|
||||
auto dba = dbms_.active();
|
||||
GraphDbAccessor dba(db_);
|
||||
bool found = false;
|
||||
for (const auto &vertex : dba->Vertices(dba->Label("Comment"), false)) {
|
||||
auto id_prop = query::TypedValue(vertex.PropsAt(dba->Property("id")));
|
||||
auto browser = query::TypedValue(vertex.PropsAt(dba->Property("browser")));
|
||||
for (const auto &vertex : dba.Vertices(dba.Label("Comment"), false)) {
|
||||
auto id_prop = query::TypedValue(vertex.PropsAt(dba.Property("id")));
|
||||
auto browser = query::TypedValue(vertex.PropsAt(dba.Property("browser")));
|
||||
if (id_prop.IsString() && id_prop.Value<std::string>() == "2") {
|
||||
EXPECT_FALSE(found);
|
||||
found = true;
|
||||
@ -53,10 +55,10 @@ TEST_F(RecoveryTest, TestPropertyNull) {
|
||||
}
|
||||
|
||||
TEST_F(RecoveryTest, TestEdgesRecovered) {
|
||||
auto dba = dbms_.active();
|
||||
EXPECT_EQ(dba->EdgesCount(), 5);
|
||||
for (const auto &edge : dba->Edges(false)) {
|
||||
EXPECT_TRUE(edge.EdgeType() == dba->EdgeType("POSTED_ON"));
|
||||
GraphDbAccessor dba(db_);
|
||||
EXPECT_EQ(dba.EdgesCount(), 5);
|
||||
for (const auto &edge : dba.Edges(false)) {
|
||||
EXPECT_TRUE(edge.EdgeType() == dba.EdgeType("POSTED_ON"));
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user