Files
memgraph/src/storage/v3/expr.cpp

211 lines
8.2 KiB
C++

// Copyright 2022 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
// License, and you may not use this file except in compliance with the Business Source License.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.
#include "storage/v3/expr.hpp"
#include <vector>
#include "db_accessor.hpp"
#include "opencypher/parser.hpp"
#include "query/v2/requests.hpp"
#include "storage/v3/bindings/ast/ast.hpp"
#include "storage/v3/bindings/bindings.hpp"
#include "storage/v3/bindings/cypher_main_visitor.hpp"
#include "storage/v3/bindings/db_accessor.hpp"
#include "storage/v3/bindings/eval.hpp"
#include "storage/v3/bindings/frame.hpp"
#include "storage/v3/bindings/symbol_generator.hpp"
#include "storage/v3/bindings/symbol_table.hpp"
#include "storage/v3/bindings/typed_value.hpp"
#include "storage/v3/value_conversions.hpp"
namespace memgraph::storage::v3 {
msgs::Value ConstructValueVertex(const VertexAccessor &acc, View view) {
// Get the vertex id
auto prim_label = acc.PrimaryLabel(view).GetValue();
memgraph::msgs::Label value_label{.id = prim_label};
auto prim_key = conversions::ConvertValueVector(acc.PrimaryKey(view).GetValue());
memgraph::msgs::VertexId vertex_id = std::make_pair(value_label, prim_key);
// Get the labels
auto vertex_labels = acc.Labels(view).GetValue();
std::vector<memgraph::msgs::Label> value_labels;
value_labels.reserve(vertex_labels.size());
std::transform(vertex_labels.begin(), vertex_labels.end(), std::back_inserter(value_labels),
[](const auto &label) { return msgs::Label{.id = label}; });
return msgs::Value({.id = vertex_id, .labels = value_labels});
}
msgs::Value ConstructValueEdge(const EdgeAccessor &acc, View view) {
msgs::EdgeType type = {.id = acc.EdgeType()};
msgs::EdgeId gid = {.gid = acc.Gid().AsUint()};
msgs::Label src_prim_label = {.id = acc.From().primary_label};
memgraph::msgs::VertexId src_vertex =
std::make_pair(src_prim_label, conversions::ConvertValueVector(acc.From().primary_key));
msgs::Label dst_prim_label = {.id = acc.To().primary_label};
msgs::VertexId dst_vertex = std::make_pair(dst_prim_label, conversions::ConvertValueVector(acc.To().primary_key));
auto properties = acc.Properties(view);
std::vector<std::pair<PropertyId, msgs::Value>> present_properties;
if (properties.HasValue()) {
auto props = properties.GetValue();
std::vector<std::pair<PropertyId, msgs::Value>> present_properties;
present_properties.reserve(props.size());
std::transform(props.begin(), props.end(), std::back_inserter(present_properties),
[](std::pair<const PropertyId, PropertyValue> &prop) {
return std::make_pair(prop.first, conversions::FromPropertyValueToValue(std::move(prop.second)));
});
}
return msgs::Value(msgs::Edge{.src = std::move(src_vertex),
.dst = std::move(dst_vertex),
.properties = std::move(present_properties),
.id = gid,
.type = type});
}
msgs::Value FromTypedValueToValue(TypedValue &&tv) {
switch (tv.type()) {
case TypedValue::Type::Bool:
return msgs::Value(tv.ValueBool());
case TypedValue::Type::Double:
return msgs::Value(tv.ValueDouble());
case TypedValue::Type::Int:
return msgs::Value(tv.ValueInt());
case TypedValue::Type::List: {
std::vector<msgs::Value> list;
auto &tv_list = tv.ValueList();
list.reserve(tv_list.size());
std::transform(tv_list.begin(), tv_list.end(), std::back_inserter(list),
[](auto &elem) { return FromTypedValueToValue(std::move(elem)); });
return msgs::Value(list);
}
case TypedValue::Type::Map: {
std::map<std::string, msgs::Value> map;
for (auto &[key, val] : tv.ValueMap()) {
map.emplace(key, FromTypedValueToValue(std::move(val)));
}
return msgs::Value(map);
}
case TypedValue::Type::Null:
return {};
case TypedValue::Type::String:
return msgs::Value((std::string(tv.ValueString())));
case TypedValue::Type::Vertex:
return ConstructValueVertex(tv.ValueVertex(), View::OLD);
case TypedValue::Type::Edge:
return ConstructValueEdge(tv.ValueEdge(), View::OLD);
// TBD -> we need to specify temporal types, not a priority.
case TypedValue::Type::Date:
case TypedValue::Type::LocalTime:
case TypedValue::Type::LocalDateTime:
case TypedValue::Type::Duration:
case TypedValue::Type::Path: {
MG_ASSERT(false, "This conversion between TypedValue and Value is not implemented yet!");
break;
}
}
return {};
}
std::vector<msgs::Value> ConvertToValueVectorFromTypedValueVector(
std::vector<memgraph::storage::v3::TypedValue> &&vec) {
std::vector<msgs::Value> ret;
ret.reserve(vec.size());
std::transform(vec.begin(), vec.end(), std::back_inserter(ret),
[](auto &elem) { return FromTypedValueToValue(std::move(elem)); });
return ret;
}
std::vector<PropertyId> NamesToProperties(const std::vector<std::string> &property_names, DbAccessor &dba) {
std::vector<PropertyId> properties;
properties.reserve(property_names.size());
for (const auto &name : property_names) {
properties.push_back(dba.NameToProperty(name));
}
return properties;
}
std::vector<memgraph::storage::v3::LabelId> NamesToLabels(const std::vector<std::string> &label_names,
DbAccessor &dba) {
std::vector<memgraph::storage::v3::LabelId> labels;
labels.reserve(label_names.size());
for (const auto &name : label_names) {
labels.push_back(dba.NameToLabel(name));
}
return labels;
}
std::any ParseExpression(const std::string &expr, memgraph::expr::AstStorage &storage) {
memgraph::frontend::opencypher::Parser<memgraph::frontend::opencypher::ParserOpTag::EXPRESSION> parser(expr);
ParsingContext pc;
CypherMainVisitor visitor(pc, &storage);
auto *ast = parser.tree();
return visitor.visit(ast);
}
TypedValue ComputeExpression(DbAccessor &dba, const memgraph::storage::v3::VertexAccessor &v_acc,
const std::optional<memgraph::storage::v3::EdgeAccessor> &e_acc,
const std::string &expression, std::string_view node_name, std::string_view edge_name) {
AstStorage storage;
Frame frame{1 + 1}; // 1 for the node_identifier, 1 for the edge_identifier
SymbolTable symbol_table;
EvaluationContext ctx;
ExpressionEvaluator eval{&frame, symbol_table, ctx, &dba, View::OLD};
auto expr = ParseExpression(expression, storage);
auto node_identifier = Identifier(std::string(node_name), false);
auto edge_identifier = Identifier(std::string(edge_name), false);
std::vector<Identifier *> identifiers;
identifiers.push_back(&node_identifier);
identifiers.push_back(&edge_identifier);
expr::SymbolGenerator symbol_generator(&symbol_table, identifiers);
(std::any_cast<Expression *>(expr))->Accept(symbol_generator);
if (node_identifier.symbol_pos_ != -1) {
MG_ASSERT(std::find_if(symbol_table.table().begin(), symbol_table.table().end(),
[&node_name](const std::pair<int32_t, Symbol> &position_symbol_pair) {
return position_symbol_pair.second.name() == node_name;
}) != symbol_table.table().end());
frame[symbol_table.at(node_identifier)] = v_acc;
}
if (edge_identifier.symbol_pos_ != -1) {
MG_ASSERT(e_acc.has_value());
MG_ASSERT(std::find_if(symbol_table.table().begin(), symbol_table.table().end(),
[&edge_name](const std::pair<int32_t, Symbol> &position_symbol_pair) {
return position_symbol_pair.second.name() == edge_name;
}) != symbol_table.table().end());
frame[symbol_table.at(edge_identifier)] = *e_acc;
}
return Eval(std::any_cast<Expression *>(expr), ctx, storage, eval, dba);
}
} // namespace memgraph::storage::v3