Add generating Capnp schema in LCP
Summary: Add additional structs and functions for handling C++ meta information. Add capnp-file and capnp-id arguments to lcp:process-file. Generate cpp along with hpp and capnp in lcp. Wrap LogicalOperator base class in lcp:define-class. Modify logical operators for capnp serialization. Add query/common.capnp. Reviewers: mculinovic, buda, mtomic, msantl, ipaljak, dgleich, mferencevic Reviewed By: msantl Subscribers: pullbot Differential Revision: https://phabricator.memgraph.io/D1391
This commit is contained in:
parent
c7b6cae526
commit
e56ed0acce
4
.gitignore
vendored
4
.gitignore
vendored
@ -38,5 +38,7 @@ TAGS
|
||||
*.capnp.c++
|
||||
*.capnp.h
|
||||
|
||||
# LCP generated C++ files
|
||||
# LCP generated C++ & Cap'n Proto files
|
||||
src/query/plan/operator.hpp
|
||||
src/query/plan/operator.lcp.cpp
|
||||
src/query/plan/operator.capnp
|
||||
|
@ -73,30 +73,6 @@ set(memgraph_src_files
|
||||
)
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# Lisp C++ Preprocessing
|
||||
|
||||
set(lcp_exe ${CMAKE_SOURCE_DIR}/tools/lcp)
|
||||
set(lcp_src_files lisp/lcp.lisp ${lcp_exe})
|
||||
|
||||
# Use this function to add each lcp file to generation. This way each file is
|
||||
# standalone and we avoid recompiling everything.
|
||||
# NOTE: Only .hpp files are generated from .lcp, so there's no need to update memgraph_src_files.
|
||||
# NOTE: generated_lcp_files are globally updated.
|
||||
function(add_lcp lcp_file)
|
||||
string(REGEX REPLACE "\.lcp$" ".hpp" h_file
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/${lcp_file}")
|
||||
add_custom_command(OUTPUT ${h_file}
|
||||
COMMAND ${lcp_exe} ${lcp_file} > ${h_file}
|
||||
DEPENDS ${lcp_file} ${lcp_src_files}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
# Update *global* generated_lcp_files
|
||||
set(generated_lcp_files ${generated_lcp_files} ${h_file} PARENT_SCOPE)
|
||||
endfunction(add_lcp)
|
||||
|
||||
add_lcp(query/plan/operator.lcp)
|
||||
|
||||
add_custom_target(generate_lcp DEPENDS ${generated_lcp_files})
|
||||
|
||||
# Use this function to add each capnp file to generation. This way each file is
|
||||
# standalone and we avoid recompiling everything.
|
||||
# NOTE: memgraph_src_files and generated_capnp_files are globally updated.
|
||||
@ -105,7 +81,7 @@ function(add_capnp capnp_src_file)
|
||||
set(h_file ${CMAKE_CURRENT_SOURCE_DIR}/${capnp_src_file}.h)
|
||||
add_custom_command(OUTPUT ${cpp_file} ${h_file}
|
||||
COMMAND ${CAPNP_EXE} compile -o${CAPNP_CXX_EXE} ${capnp_src_file} -I ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
DEPENDS ${capnp_src_file} capnproto-proj
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${capnp_src_file} capnproto-proj
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
# Update *global* generated_capnp_files
|
||||
set(generated_capnp_files ${generated_capnp_files} ${cpp_file} ${h_file} PARENT_SCOPE)
|
||||
@ -113,12 +89,52 @@ function(add_capnp capnp_src_file)
|
||||
set(memgraph_src_files ${memgraph_src_files} ${cpp_file} PARENT_SCOPE)
|
||||
endfunction(add_capnp)
|
||||
|
||||
# Lisp C++ Preprocessing
|
||||
|
||||
set(lcp_exe ${CMAKE_SOURCE_DIR}/tools/lcp)
|
||||
set(lcp_src_files lisp/lcp.lisp ${lcp_exe})
|
||||
|
||||
# Use this function to add each lcp file to generation. This way each file is
|
||||
# standalone and we avoid recompiling everything.
|
||||
# NOTE: memgraph_src_files and generated_lcp_files are globally updated.
|
||||
function(add_lcp lcp_file)
|
||||
set(options CAPNP_SCHEMA)
|
||||
cmake_parse_arguments(KW "${options}" "" "" ${ARGN})
|
||||
string(REGEX REPLACE "\.lcp$" ".hpp" h_file
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/${lcp_file}")
|
||||
if (KW_CAPNP_SCHEMA)
|
||||
string(REGEX REPLACE "\.lcp$" ".capnp" capnp_file
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/${lcp_file}")
|
||||
set(capnp_id_command ${CAPNP_EXE})
|
||||
set(capnp_depend capnproto-proj)
|
||||
set(cpp_file ${CMAKE_CURRENT_SOURCE_DIR}/${lcp_file}.cpp)
|
||||
# Update *global* memgraph_src_files
|
||||
set(memgraph_src_files ${memgraph_src_files} ${cpp_file} PARENT_SCOPE)
|
||||
endif()
|
||||
add_custom_command(OUTPUT ${h_file} ${cpp_file} ${capnp_file}
|
||||
COMMAND ${lcp_exe} ${lcp_file} ${capnp_id_command}
|
||||
VERBATIM
|
||||
DEPENDS ${lcp_file} ${lcp_src_files} ${capnp_depend}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
# Update *global* generated_lcp_files
|
||||
set(generated_lcp_files ${generated_lcp_files} ${h_file} ${cpp_file} ${capnp_file} PARENT_SCOPE)
|
||||
endfunction(add_lcp)
|
||||
|
||||
add_lcp(query/plan/operator.lcp CAPNP_SCHEMA)
|
||||
add_capnp(query/plan/operator.capnp)
|
||||
|
||||
add_custom_target(generate_lcp DEPENDS ${generated_lcp_files})
|
||||
|
||||
# Registering capnp must come after registering lcp files.
|
||||
|
||||
add_capnp(query/frontend/semantic/symbol.capnp)
|
||||
add_capnp(query/frontend/ast/ast.capnp)
|
||||
add_capnp(utils/serialization.capnp)
|
||||
add_capnp(storage/types.capnp)
|
||||
add_capnp(query/common.capnp)
|
||||
|
||||
add_custom_target(generate_capnp DEPENDS generate_lcp ${generated_capnp_files})
|
||||
|
||||
add_custom_target(generate_capnp DEPENDS ${generated_capnp_files})
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
string(TOLOWER ${CMAKE_BUILD_TYPE} lower_build_type)
|
||||
|
1081
src/lisp/lcp.lisp
1081
src/lisp/lcp.lisp
File diff suppressed because it is too large
Load Diff
15
src/query/common.capnp
Normal file
15
src/query/common.capnp
Normal file
@ -0,0 +1,15 @@
|
||||
@0xcbc2c66202fdf643;
|
||||
|
||||
using Cxx = import "/capnp/c++.capnp";
|
||||
$Cxx.namespace("query::capnp");
|
||||
|
||||
using Ast = import "/query/frontend/ast/ast.capnp";
|
||||
|
||||
enum GraphView {
|
||||
old @0;
|
||||
new @1;
|
||||
}
|
||||
|
||||
struct TypedValueVectorCompare {
|
||||
ordering @0 :List(Ast.Ordering);
|
||||
}
|
@ -8,6 +8,7 @@
|
||||
#include "glog/logging.h"
|
||||
|
||||
#include "query/exceptions.hpp"
|
||||
#include "utils/serialization.hpp"
|
||||
#include "utils/string.hpp"
|
||||
|
||||
namespace query {
|
||||
@ -280,6 +281,28 @@ bool TypedValueVectorCompare::TypedValueCompare(const TypedValue &a,
|
||||
}
|
||||
}
|
||||
|
||||
void TypedValueVectorCompare::Save(
|
||||
capnp::TypedValueVectorCompare::Builder *builder) const {
|
||||
auto ordering_builder = builder->initOrdering(ordering_.size());
|
||||
for (size_t i = 0; i < ordering_.size(); ++i) {
|
||||
ordering_builder.set(i, ordering_[i] == Ordering::ASC
|
||||
? capnp::Ordering::ASC
|
||||
: capnp::Ordering::DESC);
|
||||
}
|
||||
}
|
||||
|
||||
void TypedValueVectorCompare::Load(
|
||||
const capnp::TypedValueVectorCompare::Reader &reader) {
|
||||
std::vector<Ordering> ordering;
|
||||
ordering.reserve(reader.getOrdering().size());
|
||||
for (auto ordering_reader : reader.getOrdering()) {
|
||||
ordering.push_back(ordering_reader == capnp::Ordering::ASC
|
||||
? Ordering::ASC
|
||||
: Ordering::DESC);
|
||||
}
|
||||
ordering_ = ordering;
|
||||
}
|
||||
|
||||
template <typename TAccessor>
|
||||
void SwitchAccessor(TAccessor &accessor, GraphView graph_view) {
|
||||
switch (graph_view) {
|
||||
|
@ -7,6 +7,8 @@
|
||||
#include "query/frontend/ast/ast.hpp"
|
||||
#include "query/typed_value.hpp"
|
||||
|
||||
#include "query/common.capnp.h"
|
||||
|
||||
namespace query {
|
||||
|
||||
// These are the functions for parsing literals and parameter names from
|
||||
@ -37,7 +39,7 @@ void ReconstructTypedValue(TypedValue &value);
|
||||
// Does lexicographical ordering of elements based on the above
|
||||
// defined TypedValueCompare, and also accepts a vector of Orderings
|
||||
// the define how respective elements compare.
|
||||
class TypedValueVectorCompare {
|
||||
class TypedValueVectorCompare final {
|
||||
public:
|
||||
TypedValueVectorCompare() {}
|
||||
explicit TypedValueVectorCompare(const std::vector<Ordering> &ordering)
|
||||
@ -47,6 +49,9 @@ class TypedValueVectorCompare {
|
||||
|
||||
const auto &ordering() const { return ordering_; }
|
||||
|
||||
void Save(capnp::TypedValueVectorCompare::Builder *builder) const;
|
||||
void Load(const capnp::TypedValueVectorCompare::Reader &reader);
|
||||
|
||||
private:
|
||||
std::vector<Ordering> ordering_;
|
||||
|
||||
|
@ -309,7 +309,7 @@ void MapLiteral::Save(capnp::BaseLiteral::Builder *base_literal_builder,
|
||||
auto key_builder = entry_builder.getKey();
|
||||
key_builder.setFirst(entry.first.first);
|
||||
auto storage_property_builder = key_builder.getSecond();
|
||||
entry.first.second.Save(storage_property_builder);
|
||||
entry.first.second.Save(&storage_property_builder);
|
||||
auto value_builder = entry_builder.getValue();
|
||||
if (entry.second) entry.second->Save(&value_builder, saved_uids);
|
||||
++i;
|
||||
@ -976,11 +976,10 @@ void LabelsTest::Save(capnp::LabelsTest::Builder *builder,
|
||||
auto expr_builder = builder->initExpression();
|
||||
expression_->Save(&expr_builder, saved_uids);
|
||||
}
|
||||
::capnp::List<storage::capnp::Common>::Builder common_builders =
|
||||
builder->initLabels(labels_.size());
|
||||
auto common_builders = builder->initLabels(labels_.size());
|
||||
for (size_t i = 0; i < labels_.size(); ++i) {
|
||||
auto common_builder = common_builders[i];
|
||||
labels_[i].Save(common_builder);
|
||||
labels_[i].Save(&common_builder);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1040,7 +1039,7 @@ void PropertyLookup::Save(capnp::PropertyLookup::Builder *builder,
|
||||
}
|
||||
builder->setPropertyName(property_name_);
|
||||
auto storage_property_builder = builder->initProperty();
|
||||
property_.Save(storage_property_builder);
|
||||
property_.Save(&storage_property_builder);
|
||||
}
|
||||
|
||||
void PropertyLookup::Load(const capnp::Tree::Reader &base_reader,
|
||||
@ -1297,9 +1296,9 @@ void CreateIndex::Save(capnp::Clause::Builder *builder,
|
||||
void CreateIndex::Save(capnp::CreateIndex::Builder *builder,
|
||||
std::vector<int> *saved_uids) {
|
||||
auto label_builder = builder->getLabel();
|
||||
label_.Save(label_builder);
|
||||
label_.Save(&label_builder);
|
||||
auto property_builder = builder->getProperty();
|
||||
property_.Save(property_builder);
|
||||
property_.Save(&property_builder);
|
||||
}
|
||||
|
||||
CreateIndex *CreateIndex::Construct(const capnp::CreateIndex::Reader &reader,
|
||||
@ -1458,13 +1457,13 @@ void RemoveLabels::Save(capnp::RemoveLabels::Builder *builder,
|
||||
auto id_builder = builder->getIdentifier();
|
||||
identifier_->Save(&id_builder, saved_uids);
|
||||
}
|
||||
::capnp::List<storage::capnp::Common>::Builder common_builders =
|
||||
builder->initLabels(labels_.size());
|
||||
auto common_builders = builder->initLabels(labels_.size());
|
||||
for (size_t i = 0; i < labels_.size(); ++i) {
|
||||
auto common_builder = common_builders[i];
|
||||
labels_[i].Save(common_builder);
|
||||
labels_[i].Save(&common_builder);
|
||||
}
|
||||
}
|
||||
|
||||
void RemoveLabels::Load(const capnp::Tree::Reader &base_reader,
|
||||
AstTreeStorage *storage,
|
||||
std::vector<int> *loaded_uids) {
|
||||
@ -1628,11 +1627,10 @@ void SetLabels::Save(capnp::SetLabels::Builder *builder,
|
||||
auto id_builder = builder->getIdentifier();
|
||||
identifier_->Save(&id_builder, saved_uids);
|
||||
}
|
||||
::capnp::List<storage::capnp::Common>::Builder common_builders =
|
||||
builder->initLabels(labels_.size());
|
||||
auto common_builders = builder->initLabels(labels_.size());
|
||||
for (size_t i = 0; i < labels_.size(); ++i) {
|
||||
auto common_builder = common_builders[i];
|
||||
labels_[i].Save(common_builder);
|
||||
labels_[i].Save(&common_builder);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1827,11 +1825,10 @@ void CypherUnion::Save(capnp::CypherUnion::Builder *builder,
|
||||
single_query_->Save(&sq_builder, saved_uids);
|
||||
}
|
||||
builder->setDistinct(distinct_);
|
||||
::capnp::List<capnp::Symbol>::Builder symbol_builders =
|
||||
builder->initUnionSymbols(union_symbols_.size());
|
||||
auto symbol_builders = builder->initUnionSymbols(union_symbols_.size());
|
||||
for (size_t i = 0; i < union_symbols_.size(); ++i) {
|
||||
auto symbol_builder = symbol_builders[i];
|
||||
union_symbols_[i].Save(symbol_builder);
|
||||
union_symbols_[i].Save(&symbol_builder);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2007,16 +2004,15 @@ void NodeAtom::Save(capnp::NodeAtom::Builder *builder,
|
||||
auto key_builder = entry_builder.getKey();
|
||||
key_builder.setFirst(entry.first.first);
|
||||
auto storage_property_builder = key_builder.getSecond();
|
||||
entry.first.second.Save(storage_property_builder);
|
||||
entry.first.second.Save(&storage_property_builder);
|
||||
auto value_builder = entry_builder.getValue();
|
||||
if (entry.second) entry.second->Save(&value_builder, saved_uids);
|
||||
++i;
|
||||
}
|
||||
::capnp::List<storage::capnp::Common>::Builder common_builders =
|
||||
builder->initLabels(labels_.size());
|
||||
auto common_builders = builder->initLabels(labels_.size());
|
||||
for (size_t i = 0; i < labels_.size(); ++i) {
|
||||
auto common_builder = common_builders[i];
|
||||
labels_[i].Save(common_builder);
|
||||
labels_[i].Save(&common_builder);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2102,11 +2098,10 @@ void EdgeAtom::Save(capnp::EdgeAtom::Builder *builder,
|
||||
break;
|
||||
}
|
||||
|
||||
::capnp::List<storage::capnp::Common>::Builder common_builders =
|
||||
builder->initEdgeTypes(edge_types_.size());
|
||||
auto common_builders = builder->initEdgeTypes(edge_types_.size());
|
||||
for (size_t i = 0; i < edge_types_.size(); ++i) {
|
||||
auto common_builder = common_builders[i];
|
||||
edge_types_[i].Save(common_builder);
|
||||
edge_types_[i].Save(&common_builder);
|
||||
}
|
||||
|
||||
::capnp::List<capnp::EdgeAtom::Entry>::Builder map_builder =
|
||||
@ -2117,7 +2112,7 @@ void EdgeAtom::Save(capnp::EdgeAtom::Builder *builder,
|
||||
auto key_builder = entry_builder.getKey();
|
||||
key_builder.setFirst(entry.first.first);
|
||||
auto storage_property_builder = key_builder.getSecond();
|
||||
entry.first.second.Save(storage_property_builder);
|
||||
entry.first.second.Save(&storage_property_builder);
|
||||
auto value_builder = entry_builder.getValue();
|
||||
if (entry.second) entry.second->Save(&value_builder, saved_uids);
|
||||
++i;
|
||||
|
@ -42,29 +42,29 @@ class Symbol {
|
||||
bool user_declared() const { return user_declared_; }
|
||||
int token_position() const { return token_position_; }
|
||||
|
||||
void Save(capnp::Symbol::Builder &builder) {
|
||||
builder.setName(name_);
|
||||
builder.setPosition(position_);
|
||||
builder.setUserDeclared(user_declared_);
|
||||
builder.setTokenPosition(token_position_);
|
||||
void Save(capnp::Symbol::Builder *builder) const {
|
||||
builder->setName(name_);
|
||||
builder->setPosition(position_);
|
||||
builder->setUserDeclared(user_declared_);
|
||||
builder->setTokenPosition(token_position_);
|
||||
switch (type_) {
|
||||
case Type::Any:
|
||||
builder.setType(capnp::Symbol::Type::ANY);
|
||||
builder->setType(capnp::Symbol::Type::ANY);
|
||||
break;
|
||||
case Type::Edge:
|
||||
builder.setType(capnp::Symbol::Type::EDGE);
|
||||
builder->setType(capnp::Symbol::Type::EDGE);
|
||||
break;
|
||||
case Type::EdgeList:
|
||||
builder.setType(capnp::Symbol::Type::EDGE_LIST);
|
||||
builder->setType(capnp::Symbol::Type::EDGE_LIST);
|
||||
break;
|
||||
case Type::Number:
|
||||
builder.setType(capnp::Symbol::Type::NUMBER);
|
||||
builder->setType(capnp::Symbol::Type::NUMBER);
|
||||
break;
|
||||
case Type::Path:
|
||||
builder.setType(capnp::Symbol::Type::PATH);
|
||||
builder->setType(capnp::Symbol::Type::PATH);
|
||||
break;
|
||||
case Type::Vertex:
|
||||
builder.setType(capnp::Symbol::Type::VERTEX);
|
||||
builder->setType(capnp::Symbol::Type::VERTEX);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -56,11 +56,11 @@ class Common : public utils::TotalOrdering<TSpecificType> {
|
||||
size_t operator()(const TSpecificType &t) const { return hash(t.id_); }
|
||||
};
|
||||
|
||||
virtual void Save(capnp::Common::Builder &builder) const {
|
||||
builder.setStorage(id_);
|
||||
virtual void Save(capnp::Common::Builder *builder) const {
|
||||
builder->setStorage(id_);
|
||||
}
|
||||
|
||||
virtual void Load(capnp::Common::Reader &reader) {
|
||||
virtual void Load(const capnp::Common::Reader &reader) {
|
||||
id_ = reader.getStorage();
|
||||
}
|
||||
|
||||
|
@ -62,7 +62,8 @@ struct SharedPtr(T) {
|
||||
}
|
||||
}
|
||||
|
||||
# TypedValue.
|
||||
# Our types
|
||||
|
||||
struct TypedValue {
|
||||
union {
|
||||
nullType @0 :Void;
|
||||
@ -82,3 +83,13 @@ struct TypedValue {
|
||||
value @1 :TypedValue;
|
||||
}
|
||||
}
|
||||
|
||||
struct Bound(T) {
|
||||
type @0 :Type;
|
||||
value @1 :T;
|
||||
|
||||
enum Type {
|
||||
inclusive @0;
|
||||
exclusive @1;
|
||||
}
|
||||
}
|
||||
|
@ -203,13 +203,13 @@ inline void SaveUniquePtr(
|
||||
template <typename TCapnp, typename T>
|
||||
inline std::unique_ptr<T> LoadUniquePtr(
|
||||
const typename capnp::UniquePtr<TCapnp>::Reader &reader,
|
||||
const std::function<T(const typename TCapnp::Reader &reader)> &load) {
|
||||
const std::function<T*(const typename TCapnp::Reader &reader)> &load) {
|
||||
switch (reader.which()) {
|
||||
case capnp::UniquePtr<TCapnp>::NULLPTR:
|
||||
return nullptr;
|
||||
case capnp::UniquePtr<TCapnp>::VALUE:
|
||||
auto value_reader = reader.getValue();
|
||||
return std::make_unique<T>(load(value_reader));
|
||||
return std::unique_ptr<T>(load(value_reader));
|
||||
}
|
||||
}
|
||||
|
||||
@ -236,9 +236,9 @@ inline void SaveSharedPtr(
|
||||
}
|
||||
|
||||
template <typename TCapnp, typename T>
|
||||
inline std::shared_ptr<T> LoadSharedPtr(
|
||||
std::shared_ptr<T> LoadSharedPtr(
|
||||
const typename capnp::SharedPtr<TCapnp>::Reader &reader,
|
||||
const std::function<T(const typename TCapnp::Reader &reader)> &load,
|
||||
const std::function<T *(const typename TCapnp::Reader &reader)> &load,
|
||||
std::vector<std::pair<uint64_t, std::shared_ptr<T>>> *loaded_pointers) {
|
||||
std::shared_ptr<T> ret;
|
||||
switch (reader.which()) {
|
||||
@ -255,7 +255,7 @@ inline std::shared_ptr<T> LoadSharedPtr(
|
||||
});
|
||||
if (found != loaded_pointers->end()) return found->second;
|
||||
auto value_reader = entry_reader.getValue();
|
||||
ret = std::make_shared<T>(load(value_reader));
|
||||
ret = std::shared_ptr<T>(load(value_reader));
|
||||
loaded_pointers->emplace_back(std::make_pair(pointer_id, ret));
|
||||
}
|
||||
return ret;
|
||||
|
@ -19,7 +19,6 @@
|
||||
#include "query/typed_value.hpp"
|
||||
|
||||
#include "capnp/message.h"
|
||||
#include "capnp/serialize-packed.h"
|
||||
#include "query/frontend/ast/ast.capnp.h"
|
||||
|
||||
namespace {
|
||||
|
@ -17,6 +17,9 @@
|
||||
#include "query/plan/operator.hpp"
|
||||
#include "query/plan/planner.hpp"
|
||||
|
||||
#include "capnp/message.h"
|
||||
#include "query/plan/operator.capnp.h"
|
||||
|
||||
#include "query_common.hpp"
|
||||
|
||||
namespace query {
|
||||
@ -505,6 +508,42 @@ class SerializedPlanner {
|
||||
std::unique_ptr<LogicalOperator> plan_;
|
||||
};
|
||||
|
||||
void SavePlan(const LogicalOperator &plan, ::capnp::MessageBuilder *message) {
|
||||
auto builder = message->initRoot<query::plan::capnp::LogicalOperator>();
|
||||
LogicalOperator::SaveHelper helper;
|
||||
plan.Save(&builder, &helper);
|
||||
}
|
||||
|
||||
auto LoadPlan(const ::query::plan::capnp::LogicalOperator::Reader &reader) {
|
||||
auto plan = LogicalOperator::Construct(reader);
|
||||
LogicalOperator::LoadHelper helper;
|
||||
plan->Load(reader, &helper);
|
||||
return std::make_pair(std::move(plan), std::move(helper.ast_storage));
|
||||
}
|
||||
|
||||
class CapnpPlanner {
|
||||
public:
|
||||
CapnpPlanner(std::vector<SingleQueryPart> single_query_parts,
|
||||
PlanningContext<database::GraphDbAccessor> &context) {
|
||||
::capnp::MallocMessageBuilder message;
|
||||
{
|
||||
auto original_plan = MakeLogicalPlanForSingleQuery<RuleBasedPlanner>(
|
||||
single_query_parts, context);
|
||||
SavePlan(*original_plan, &message);
|
||||
}
|
||||
{
|
||||
auto reader = message.getRoot<query::plan::capnp::LogicalOperator>();
|
||||
std::tie(plan_, ast_storage_) = LoadPlan(reader);
|
||||
}
|
||||
}
|
||||
|
||||
auto &plan() { return *plan_; }
|
||||
|
||||
private:
|
||||
AstTreeStorage ast_storage_;
|
||||
std::unique_ptr<LogicalOperator> plan_;
|
||||
};
|
||||
|
||||
template <class TPlanner>
|
||||
TPlanner MakePlanner(database::MasterBase &master_db, AstTreeStorage &storage,
|
||||
SymbolTable &symbol_table) {
|
||||
@ -637,7 +676,7 @@ ExpectedDistributedPlan ExpectDistributed(
|
||||
template <class T>
|
||||
class TestPlanner : public ::testing::Test {};
|
||||
|
||||
using PlannerTypes = ::testing::Types<Planner, SerializedPlanner>;
|
||||
using PlannerTypes = ::testing::Types<Planner, SerializedPlanner, CapnpPlanner>;
|
||||
|
||||
TYPED_TEST_CASE(TestPlanner, PlannerTypes);
|
||||
|
||||
@ -2234,4 +2273,111 @@ TYPED_TEST(TestPlanner, DistributedCartesianCreate) {
|
||||
CheckDistributedPlan(planner.plan(), symbol_table, expected);
|
||||
}
|
||||
|
||||
TEST(CapnpSerial, Union) {
|
||||
std::vector<Symbol> left_symbols{
|
||||
Symbol("symbol", 1, true, Symbol::Type::Edge)};
|
||||
std::vector<Symbol> right_symbols{
|
||||
Symbol("symbol", 3, true, Symbol::Type::Any)};
|
||||
auto union_symbols = right_symbols;
|
||||
auto union_op = std::make_unique<Union>(nullptr, nullptr, union_symbols,
|
||||
left_symbols, right_symbols);
|
||||
std::unique_ptr<LogicalOperator> loaded_plan;
|
||||
::capnp::MallocMessageBuilder message;
|
||||
SavePlan(*union_op, &message);
|
||||
AstTreeStorage new_storage;
|
||||
std::tie(loaded_plan, new_storage) =
|
||||
LoadPlan(message.getRoot<query::plan::capnp::LogicalOperator>());
|
||||
ASSERT_TRUE(loaded_plan);
|
||||
auto *loaded_op = dynamic_cast<Union *>(loaded_plan.get());
|
||||
ASSERT_TRUE(loaded_op);
|
||||
EXPECT_FALSE(loaded_op->left_op());
|
||||
EXPECT_FALSE(loaded_op->right_op());
|
||||
EXPECT_EQ(loaded_op->left_symbols(), left_symbols);
|
||||
EXPECT_EQ(loaded_op->right_symbols(), right_symbols);
|
||||
EXPECT_EQ(loaded_op->union_symbols(), union_symbols);
|
||||
}
|
||||
|
||||
TEST(CapnpSerial, Cartesian) {
|
||||
std::vector<Symbol> left_symbols{
|
||||
Symbol("left_symbol", 1, true, Symbol::Type::Edge)};
|
||||
std::vector<Symbol> right_symbols{
|
||||
Symbol("right_symbol", 3, true, Symbol::Type::Any)};
|
||||
auto cartesian = std::make_unique<Cartesian>(nullptr, left_symbols, nullptr,
|
||||
right_symbols);
|
||||
std::unique_ptr<LogicalOperator> loaded_plan;
|
||||
::capnp::MallocMessageBuilder message;
|
||||
SavePlan(*cartesian, &message);
|
||||
AstTreeStorage new_storage;
|
||||
std::tie(loaded_plan, new_storage) =
|
||||
LoadPlan(message.getRoot<query::plan::capnp::LogicalOperator>());
|
||||
ASSERT_TRUE(loaded_plan);
|
||||
auto *loaded_op = dynamic_cast<Cartesian *>(loaded_plan.get());
|
||||
ASSERT_TRUE(loaded_op);
|
||||
EXPECT_FALSE(loaded_op->left_op());
|
||||
EXPECT_FALSE(loaded_op->right_op());
|
||||
EXPECT_EQ(loaded_op->left_symbols(), left_symbols);
|
||||
EXPECT_EQ(loaded_op->right_symbols(), right_symbols);
|
||||
}
|
||||
|
||||
TEST(CapnpSerial, Synchronize) {
|
||||
auto synchronize = std::make_unique<Synchronize>(nullptr, nullptr, true);
|
||||
std::unique_ptr<LogicalOperator> loaded_plan;
|
||||
::capnp::MallocMessageBuilder message;
|
||||
SavePlan(*synchronize, &message);
|
||||
AstTreeStorage new_storage;
|
||||
std::tie(loaded_plan, new_storage) =
|
||||
LoadPlan(message.getRoot<query::plan::capnp::LogicalOperator>());
|
||||
ASSERT_TRUE(loaded_plan);
|
||||
auto *loaded_op = dynamic_cast<Synchronize *>(loaded_plan.get());
|
||||
ASSERT_TRUE(loaded_op);
|
||||
EXPECT_FALSE(loaded_op->input());
|
||||
EXPECT_FALSE(loaded_op->pull_remote());
|
||||
EXPECT_TRUE(loaded_op->advance_command());
|
||||
}
|
||||
|
||||
TEST(CapnpSerial, PullRemote) {
|
||||
std::vector<Symbol> symbols{
|
||||
Symbol("symbol", 1, true, Symbol::Type::Edge)};
|
||||
auto pull_remote = std::make_unique<PullRemote>(nullptr, 42, symbols);
|
||||
std::unique_ptr<LogicalOperator> loaded_plan;
|
||||
::capnp::MallocMessageBuilder message;
|
||||
SavePlan(*pull_remote, &message);
|
||||
AstTreeStorage new_storage;
|
||||
std::tie(loaded_plan, new_storage) =
|
||||
LoadPlan(message.getRoot<query::plan::capnp::LogicalOperator>());
|
||||
ASSERT_TRUE(loaded_plan);
|
||||
auto *loaded_op = dynamic_cast<PullRemote *>(loaded_plan.get());
|
||||
ASSERT_TRUE(loaded_op);
|
||||
EXPECT_FALSE(loaded_op->input());
|
||||
EXPECT_EQ(loaded_op->plan_id(), 42);
|
||||
EXPECT_EQ(loaded_op->symbols(), symbols);
|
||||
}
|
||||
|
||||
TEST(CapnpSerial, PullRemoteOrderBy) {
|
||||
auto once = std::make_shared<Once>();
|
||||
AstTreeStorage storage;
|
||||
std::vector<Symbol> symbols{
|
||||
Symbol("my_symbol", 2, true, Symbol::Type::Vertex, 3)};
|
||||
std::vector<std::pair<query::Ordering, query::Expression *>> order_by{
|
||||
{query::Ordering::ASC, IDENT("my_symbol")}};
|
||||
auto pull_remote_order_by =
|
||||
std::make_unique<PullRemoteOrderBy>(once, 42, order_by, symbols);
|
||||
std::unique_ptr<LogicalOperator> loaded_plan;
|
||||
::capnp::MallocMessageBuilder message;
|
||||
SavePlan(*pull_remote_order_by, &message);
|
||||
AstTreeStorage new_storage;
|
||||
std::tie(loaded_plan, new_storage) =
|
||||
LoadPlan(message.getRoot<query::plan::capnp::LogicalOperator>());
|
||||
ASSERT_TRUE(loaded_plan);
|
||||
auto *loaded_op = dynamic_cast<PullRemoteOrderBy *>(loaded_plan.get());
|
||||
ASSERT_TRUE(loaded_op);
|
||||
ASSERT_TRUE(std::dynamic_pointer_cast<Once>(loaded_op->input()));
|
||||
EXPECT_EQ(loaded_op->plan_id(), 42);
|
||||
EXPECT_EQ(loaded_op->symbols(), symbols);
|
||||
ASSERT_EQ(loaded_op->order_by().size(), 1);
|
||||
EXPECT_TRUE(dynamic_cast<query::Identifier *>(loaded_op->order_by()[0]));
|
||||
ASSERT_EQ(loaded_op->compare().ordering().size(), 1);
|
||||
EXPECT_EQ(loaded_op->compare().ordering()[0], query::Ordering::ASC);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -91,7 +91,6 @@ void CheckOptionalInt(const std::experimental::optional<int> &x1) {
|
||||
TEST(Serialization, CapnpOptional) {
|
||||
std::experimental::optional<int> x1 = {};
|
||||
std::experimental::optional<int> x2 = 42;
|
||||
std::experimental::optional<int> y1, y2;
|
||||
|
||||
CheckOptionalInt(x1);
|
||||
CheckOptionalInt(x2);
|
||||
@ -104,13 +103,11 @@ TEST(Serialization, CapnpOptionalNonCopyable) {
|
||||
{
|
||||
auto builder = message.initRoot<utils::capnp::Optional<
|
||||
utils::capnp::UniquePtr<utils::capnp::BoxInt32>>>();
|
||||
auto save = [](
|
||||
utils::capnp::UniquePtr<utils::capnp::BoxInt32>::Builder *builder,
|
||||
const std::unique_ptr<int> &data) {
|
||||
auto save_int = [](utils::capnp::BoxInt32::Builder *builder, int value) {
|
||||
builder->setValue(value);
|
||||
auto save = [](auto *ptr_builder, const auto &data) {
|
||||
auto save_int = [](auto *int_builder, int value) {
|
||||
int_builder->setValue(value);
|
||||
};
|
||||
utils::SaveUniquePtr<utils::capnp::BoxInt32, int>(data, builder,
|
||||
utils::SaveUniquePtr<utils::capnp::BoxInt32, int>(data, ptr_builder,
|
||||
save_int);
|
||||
};
|
||||
utils::SaveOptional<utils::capnp::UniquePtr<utils::capnp::BoxInt32>,
|
||||
@ -120,13 +117,11 @@ TEST(Serialization, CapnpOptionalNonCopyable) {
|
||||
{
|
||||
auto reader = message.getRoot<utils::capnp::Optional<
|
||||
utils::capnp::UniquePtr<utils::capnp::BoxInt32>>>();
|
||||
auto load = [](
|
||||
const utils::capnp::UniquePtr<utils::capnp::BoxInt32>::Reader &reader)
|
||||
-> std::unique_ptr<int> {
|
||||
auto load_int = [](const utils::capnp::BoxInt32::Reader &reader) -> int {
|
||||
return reader.getValue();
|
||||
auto load = [](const auto &ptr_reader) {
|
||||
auto load_int = [](const auto &int_reader) {
|
||||
return new int(int_reader.getValue());
|
||||
};
|
||||
return utils::LoadUniquePtr<utils::capnp::BoxInt32, int>(reader,
|
||||
return utils::LoadUniquePtr<utils::capnp::BoxInt32, int>(ptr_reader,
|
||||
load_int);
|
||||
};
|
||||
element =
|
||||
@ -150,8 +145,8 @@ void CheckUniquePtrInt(const std::unique_ptr<int> &x1) {
|
||||
{
|
||||
auto reader =
|
||||
message.getRoot<utils::capnp::UniquePtr<utils::capnp::BoxInt32>>();
|
||||
auto load = [](const utils::capnp::BoxInt32::Reader &reader) -> int {
|
||||
return reader.getValue();
|
||||
auto load = [](const auto &int_reader) {
|
||||
return new int(int_reader.getValue());
|
||||
};
|
||||
y1 = utils::LoadUniquePtr<utils::capnp::BoxInt32, int>(reader, load);
|
||||
}
|
||||
@ -176,13 +171,11 @@ TEST(Serialization, CapnpUniquePtrNonCopyable) {
|
||||
{
|
||||
auto builder = message.initRoot<utils::capnp::UniquePtr<
|
||||
utils::capnp::UniquePtr<utils::capnp::BoxInt32>>>();
|
||||
auto save = [](
|
||||
utils::capnp::UniquePtr<utils::capnp::BoxInt32>::Builder *builder,
|
||||
const std::unique_ptr<int> &data) {
|
||||
auto save_int = [](utils::capnp::BoxInt32::Builder *builder, int value) {
|
||||
builder->setValue(value);
|
||||
auto save = [](auto *ptr_builder, const auto &data) {
|
||||
auto save_int = [](auto *int_builder, int value) {
|
||||
int_builder->setValue(value);
|
||||
};
|
||||
utils::SaveUniquePtr<utils::capnp::BoxInt32, int>(data, builder,
|
||||
utils::SaveUniquePtr<utils::capnp::BoxInt32, int>(data, ptr_builder,
|
||||
save_int);
|
||||
};
|
||||
utils::SaveUniquePtr<utils::capnp::UniquePtr<utils::capnp::BoxInt32>,
|
||||
@ -192,14 +185,13 @@ TEST(Serialization, CapnpUniquePtrNonCopyable) {
|
||||
{
|
||||
auto reader = message.getRoot<utils::capnp::UniquePtr<
|
||||
utils::capnp::UniquePtr<utils::capnp::BoxInt32>>>();
|
||||
auto load = [](
|
||||
const utils::capnp::UniquePtr<utils::capnp::BoxInt32>::Reader &reader)
|
||||
-> std::unique_ptr<int> {
|
||||
auto load_int = [](const utils::capnp::BoxInt32::Reader &reader) -> int {
|
||||
return reader.getValue();
|
||||
auto load = [](const auto &ptr_reader) {
|
||||
auto load_int = [](const auto &int_reader) {
|
||||
return new int(int_reader.getValue());
|
||||
};
|
||||
return utils::LoadUniquePtr<utils::capnp::BoxInt32, int>(reader,
|
||||
load_int);
|
||||
return new std::unique_ptr<int>(
|
||||
utils::LoadUniquePtr<utils::capnp::BoxInt32, int>(ptr_reader,
|
||||
load_int));
|
||||
};
|
||||
element =
|
||||
utils::LoadUniquePtr<utils::capnp::UniquePtr<utils::capnp::BoxInt32>,
|
||||
@ -233,8 +225,8 @@ TEST(Serialization, CapnpSharedPtr) {
|
||||
{
|
||||
auto reader = message.getRoot<
|
||||
::capnp::List<utils::capnp::SharedPtr<utils::capnp::BoxInt32>>>();
|
||||
auto load = [](const utils::capnp::BoxInt32::Reader &reader) -> int {
|
||||
return reader.getValue();
|
||||
auto load = [](const auto &int_reader) {
|
||||
return new int(int_reader.getValue());
|
||||
};
|
||||
for (const auto ptr_reader : reader) {
|
||||
elements.emplace_back(utils::LoadSharedPtr<utils::capnp::BoxInt32, int>(
|
||||
@ -256,13 +248,11 @@ TEST(Serialization, CapnpSharedPtrNonCopyable) {
|
||||
{
|
||||
auto builder = message.initRoot<utils::capnp::SharedPtr<
|
||||
utils::capnp::UniquePtr<utils::capnp::BoxInt32>>>();
|
||||
auto save = [](
|
||||
utils::capnp::UniquePtr<utils::capnp::BoxInt32>::Builder *builder,
|
||||
const std::unique_ptr<int> &data) {
|
||||
auto save_int = [](utils::capnp::BoxInt32::Builder *builder, int value) {
|
||||
builder->setValue(value);
|
||||
auto save = [](auto *ptr_builder, const auto &data) {
|
||||
auto save_int = [](auto *int_builder, int value) {
|
||||
int_builder->setValue(value);
|
||||
};
|
||||
utils::SaveUniquePtr<utils::capnp::BoxInt32, int>(data, builder,
|
||||
utils::SaveUniquePtr<utils::capnp::BoxInt32, int>(data, ptr_builder,
|
||||
save_int);
|
||||
};
|
||||
utils::SaveSharedPtr<utils::capnp::UniquePtr<utils::capnp::BoxInt32>,
|
||||
@ -275,14 +265,13 @@ TEST(Serialization, CapnpSharedPtrNonCopyable) {
|
||||
{
|
||||
auto reader = message.getRoot<utils::capnp::SharedPtr<
|
||||
utils::capnp::UniquePtr<utils::capnp::BoxInt32>>>();
|
||||
auto load = [](
|
||||
const utils::capnp::UniquePtr<utils::capnp::BoxInt32>::Reader &reader)
|
||||
-> std::unique_ptr<int> {
|
||||
auto load_int = [](const utils::capnp::BoxInt32::Reader &reader) -> int {
|
||||
return reader.getValue();
|
||||
auto load = [](const auto &ptr_reader) {
|
||||
auto load_int = [](const auto &int_reader) {
|
||||
return new int(int_reader.getValue());
|
||||
};
|
||||
return utils::LoadUniquePtr<utils::capnp::BoxInt32, int>(reader,
|
||||
load_int);
|
||||
return new std::unique_ptr<int>(
|
||||
utils::LoadUniquePtr<utils::capnp::BoxInt32, int>(ptr_reader,
|
||||
load_int));
|
||||
};
|
||||
element =
|
||||
utils::LoadSharedPtr<utils::capnp::UniquePtr<utils::capnp::BoxInt32>,
|
||||
@ -344,13 +333,11 @@ TEST(Serialization, CapnpVectorNonCopyable) {
|
||||
auto list_builder = message.initRoot<
|
||||
::capnp::List<utils::capnp::UniquePtr<utils::capnp::BoxInt32>>>(
|
||||
data.size());
|
||||
auto save = [](
|
||||
utils::capnp::UniquePtr<utils::capnp::BoxInt32>::Builder *builder,
|
||||
const std::unique_ptr<int> &data) {
|
||||
auto save_int = [](utils::capnp::BoxInt32::Builder *builder, int value) {
|
||||
builder->setValue(value);
|
||||
auto save = [](auto *ptr_builder, const auto &data) {
|
||||
auto save_int = [](auto *int_builder, int value) {
|
||||
int_builder->setValue(value);
|
||||
};
|
||||
utils::SaveUniquePtr<utils::capnp::BoxInt32, int>(data, builder,
|
||||
utils::SaveUniquePtr<utils::capnp::BoxInt32, int>(data, ptr_builder,
|
||||
save_int);
|
||||
};
|
||||
utils::SaveVector<utils::capnp::UniquePtr<utils::capnp::BoxInt32>,
|
||||
@ -360,13 +347,11 @@ TEST(Serialization, CapnpVectorNonCopyable) {
|
||||
{
|
||||
auto reader = message.getRoot<
|
||||
::capnp::List<utils::capnp::UniquePtr<utils::capnp::BoxInt32>>>();
|
||||
auto load = [](
|
||||
const utils::capnp::UniquePtr<utils::capnp::BoxInt32>::Reader &reader)
|
||||
-> std::unique_ptr<int> {
|
||||
auto load_int = [](const utils::capnp::BoxInt32::Reader &reader) -> int {
|
||||
return reader.getValue();
|
||||
auto load = [](const auto &ptr_reader) {
|
||||
auto load_int = [](const auto &int_reader) {
|
||||
return new int(int_reader.getValue());
|
||||
};
|
||||
return utils::LoadUniquePtr<utils::capnp::BoxInt32, int>(reader,
|
||||
return utils::LoadUniquePtr<utils::capnp::BoxInt32, int>(ptr_reader,
|
||||
load_int);
|
||||
};
|
||||
utils::LoadVector<utils::capnp::UniquePtr<utils::capnp::BoxInt32>,
|
||||
|
28
tools/lcp
28
tools/lcp
@ -1,8 +1,9 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
if [[ $# -ne 1 ]]; then
|
||||
echo "Usage: $0 LCP_FILE"
|
||||
echo "Convert a LCP_FILE to C++ header file and output to stdout"
|
||||
if [[ $# -ne 1 && $# -ne 2 ]]; then
|
||||
echo "Usage: $0 LCP_FILE [CAPNP_EXE]"
|
||||
echo "Convert a LCP_FILE to C++ header file and output to stdout."
|
||||
echo "If CAPNP_EXE is provided, then the Cap'n Proto schema generated."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@ -14,17 +15,28 @@ fi
|
||||
lcp_file=`realpath $1`
|
||||
script_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
|
||||
cd $script_dir
|
||||
|
||||
quicklisp_install_dir="$HOME/quicklisp"
|
||||
if [[ -v QUICKLISP_HOME ]]; then
|
||||
quicklisp_install_dir="${QUICKLISP_HOME}"
|
||||
fi
|
||||
|
||||
capnp=""
|
||||
if [[ $# -eq 2 ]]; then
|
||||
capnp=":capnp-id \"$($2 id)\""
|
||||
fi
|
||||
|
||||
echo \
|
||||
"
|
||||
(load \"${quicklisp_install_dir}/setup.lisp\")
|
||||
(ql:quickload :cl-ppcre :silent t)
|
||||
(load \"../src/lisp/lcp.lisp\")
|
||||
(lcp:process-file \"$lcp_file\" :out-stream t)
|
||||
" | sbcl --script | clang-format -style=file
|
||||
(load \"$script_dir/../src/lisp/lcp.lisp\")
|
||||
(lcp:process-file \"$lcp_file\" $capnp)
|
||||
" | sbcl --script
|
||||
|
||||
filename=`basename $lcp_file .lcp`
|
||||
hpp_file="$(dirname $lcp_file)/$filename.hpp"
|
||||
clang-format -style=file -i $hpp_file
|
||||
|
||||
if [[ $# -eq 2 ]]; then
|
||||
clang-format -style=file -i "$lcp_file.cpp"
|
||||
fi
|
||||
|
Loading…
Reference in New Issue
Block a user