Add GetProperties shard handler and tests

This commit is contained in:
Kostas Kyrimis 2022-11-16 18:41:22 +02:00
parent 5c0e41ed44
commit 9ec72bd969
5 changed files with 474 additions and 25 deletions

View File

@ -321,10 +321,6 @@ struct Expression {
std::string expression;
};
struct Filter {
std::string filter_expression;
};
enum class OrderingDirection { ASCENDING = 1, DESCENDING = 2 };
struct OrderBy {
@ -366,22 +362,42 @@ struct ScanVerticesResponse {
std::vector<ScanResultRow> results;
};
using VertexOrEdgeIds = std::variant<VertexId, EdgeId>;
struct VertexAndEdgeId {
VertexId vertex;
std::optional<EdgeTypeId> edge;
};
struct GetPropertiesRequest {
Hlc transaction_id;
// Shouldn't contain mixed vertex and edge ids
VertexOrEdgeIds vertex_or_edge_ids;
std::vector<VertexAndEdgeId> vertices_and_edges;
std::vector<PropertyId> property_ids;
std::vector<Expression> expressions;
bool only_unique = false;
std::optional<std::vector<OrderBy>> order_by;
std::vector<std::string> expressions;
std::vector<OrderBy> order_by;
std::optional<size_t> limit;
std::optional<Filter> filter;
// Return only the properties of the vertices or edges that the filter predicate
// evaluates to true
std::optional<std::string> filter;
};
struct PropIdValue {
std::vector<PropertyId> ids;
std::vector<Value> properties;
};
struct GetPropertiesResultRow {
VertexAndEdgeId vertex_and_edge;
PropIdValue properies_and_ids;
std::vector<Value> evaluated_expressions;
};
struct GetPropertiesResponse {
bool success;
std::vector<GetPropertiesResultRow> result_row;
enum RequestResult : uint16_t { OUT_OF_SHARD_RANGE, SUCCESS, FAILURE };
RequestResult result;
};
enum class EdgeDirection : uint8_t { OUT = 1, IN = 2, BOTH = 3 };

View File

@ -11,6 +11,7 @@
#include "storage/v3/request_helper.hpp"
#include <iterator>
#include <vector>
#include "pretty_print_ast_to_original_expression.hpp"
@ -43,19 +44,74 @@ std::vector<Element> OrderByElements(Shard::Accessor &acc, DbAccessor &dba, Vert
properties_order_by.reserve(order_bys.size());
for (const auto &order_by : order_bys) {
const auto val =
auto val =
ComputeExpression(dba, *it, std::nullopt, order_by.expression.expression, expr::identifier_node_symbol, "");
properties_order_by.push_back(val);
properties_order_by.push_back(std::move(val));
}
ordered.push_back({std::move(properties_order_by), *it});
}
std::sort(ordered.begin(), ordered.end(), [compare_typed_values](const auto &pair1, const auto &pair2) {
std::sort(ordered.begin(), ordered.end(), [&compare_typed_values](const auto &pair1, const auto &pair2) {
return compare_typed_values(pair1.properties_order_by, pair2.properties_order_by);
});
return ordered;
}
std::vector<GetPropElement> OrderByElements(DbAccessor &dba, std::vector<msgs::OrderBy> &order_by,
std::vector<GetPropElement> &&vertices) {
std::vector<Ordering> ordering;
ordering.reserve(order_by.size());
for (const auto &order : order_by) {
switch (order.direction) {
case memgraph::msgs::OrderingDirection::ASCENDING: {
ordering.push_back(Ordering::ASC);
break;
}
case memgraph::msgs::OrderingDirection::DESCENDING: {
ordering.push_back(Ordering::DESC);
break;
}
}
}
struct PropElement {
std::vector<TypedValue> properties_order_by;
VertexAccessor vertex_acc;
GetPropElement *original_element;
};
std::vector<PropElement> ordered;
auto compare_typed_values = TypedValueVectorCompare(ordering);
for (auto &vertex : vertices) {
std::vector<TypedValue> properties;
properties.reserve(order_by.size());
const auto *symbol = (vertex.edge_acc) ? expr::identifier_edge_symbol : expr::identifier_node_symbol;
for (const auto &order : order_by) {
TypedValue val;
if (vertex.edge_acc) {
val = ComputeExpression(dba, vertex.vertex_acc, vertex.edge_acc, order.expression.expression, "", symbol);
} else {
val = ComputeExpression(dba, vertex.vertex_acc, vertex.edge_acc, order.expression.expression, symbol, "");
}
properties.push_back(std::move(val));
}
ordered.push_back({std::move(properties), vertex.vertex_acc, &vertex});
}
std::sort(ordered.begin(), ordered.end(), [&compare_typed_values](const auto &lhs, const auto &rhs) {
return compare_typed_values(lhs.properties_order_by, rhs.properties_order_by);
});
std::vector<GetPropElement> results_ordered;
results_ordered.reserve(ordered.size());
for (auto &elem : ordered) {
results_ordered.push_back(std::move(*elem.original_element));
}
return results_ordered;
}
VerticesIterable::Iterator GetStartVertexIterator(VerticesIterable &vertex_iterable,
const std::vector<PropertyValue> &start_ids, const View view) {
auto it = vertex_iterable.begin();

View File

@ -12,6 +12,7 @@
#include <vector>
#include "ast/ast.hpp"
#include "query/v2/requests.hpp"
#include "storage/v3/bindings/typed_value.hpp"
#include "storage/v3/shard.hpp"
#include "storage/v3/vertex_accessor.hpp"
@ -104,9 +105,19 @@ struct Element {
VertexAccessor vertex_acc;
};
struct GetPropElement {
std::vector<TypedValue> properties_order_by;
std::vector<PropertyId> ids;
VertexAccessor vertex_acc;
std::optional<EdgeAccessor> edge_acc;
};
std::vector<Element> OrderByElements(Shard::Accessor &acc, DbAccessor &dba, VerticesIterable &vertices_iterable,
std::vector<msgs::OrderBy> &order_bys);
std::vector<GetPropElement> OrderByElements(DbAccessor &dba, std::vector<msgs::OrderBy> &order_bys,
std::vector<GetPropElement> &&vertices);
VerticesIterable::Iterator GetStartVertexIterator(VerticesIterable &vertex_iterable,
const std::vector<PropertyValue> &start_ids, View view);

View File

@ -15,8 +15,10 @@
#include <optional>
#include <unordered_set>
#include <utility>
#include <variant>
#include "parser/opencypher/parser.hpp"
#include "pretty_print_ast_to_original_expression.hpp"
#include "query/v2/requests.hpp"
#include "storage/v2/vertex.hpp"
#include "storage/v2/view.hpp"
@ -29,6 +31,7 @@
#include "storage/v3/bindings/symbol_generator.hpp"
#include "storage/v3/bindings/symbol_table.hpp"
#include "storage/v3/bindings/typed_value.hpp"
#include "storage/v3/conversions.hpp"
#include "storage/v3/expr.hpp"
#include "storage/v3/id_types.hpp"
#include "storage/v3/key_store.hpp"
@ -159,10 +162,15 @@ std::optional<std::map<PropertyId, Value>> CollectAllPropertiesFromAccessor(cons
}
bool FilterOnVertex(DbAccessor &dba, const storage::v3::VertexAccessor &v_acc, const std::vector<std::string> &filters,
const std::string_view node_name) {
return std::ranges::all_of(filters, [&node_name, &dba, &v_acc](const auto &filter_expr) {
auto res = ComputeExpression(dba, v_acc, std::nullopt, filter_expr, node_name, "");
return res.IsBool() && res.ValueBool();
const std::string_view node_name, const std::optional<EdgeAccessor> &e_acc = std::nullopt) {
return std::ranges::all_of(filters, [&node_name, &dba, &v_acc, &e_acc](const auto &filter_expr) {
TypedValue result;
if (e_acc) {
result = ComputeExpression(dba, v_acc, e_acc, filter_expr, "", node_name);
} else {
result = ComputeExpression(dba, v_acc, e_acc, filter_expr, node_name, "");
}
return result.IsBool() && result.ValueBool();
});
}
@ -936,9 +944,125 @@ msgs::WriteResponses ShardRsm::ApplyWrite(msgs::CommitRequest &&req) {
return msgs::CommitResponse{true};
};
// NOLINTNEXTLINE(readability-convert-member-functions-to-static)
msgs::ReadResponses ShardRsm::HandleRead(msgs::GetPropertiesRequest && /*req*/) {
return msgs::GetPropertiesResponse{};
msgs::ReadResponses ShardRsm::HandleRead(msgs::GetPropertiesRequest &&req) {
if (req.vertices_and_edges.empty()) {
return msgs::GetPropertiesResponse{.result = msgs::GetPropertiesResponse::FAILURE};
}
auto shard_acc = shard_->Access(req.transaction_id);
auto dba = DbAccessor{&shard_acc};
const auto view = storage::v3::View::NEW;
auto collect_props = [](const VertexAccessor &acc, const std::vector<PropertyId> &props, View view,
const std::optional<EdgeAccessor> &e_acc) mutable -> std::optional<GetPropElement> {
std::vector<TypedValue> properties;
std::vector<PropertyId> ids;
for (const auto &prop : props) {
Result<PropertyValue> result{PropertyValue()};
if (e_acc) {
result = e_acc->GetProperty(prop, view);
} else {
result = acc.GetProperty(prop, view);
}
if (result.HasError() && result.GetError() == Error::NONEXISTENT_OBJECT) {
continue;
}
if (result.HasError()) {
spdlog::debug("Encountered an Error while trying to get a vertex property.");
return std::nullopt;
}
properties.push_back(PropertyToTypedValue<TypedValue>(result.GetValue()));
ids.push_back(prop);
}
GetPropElement element{std::move(properties), std::move(ids), acc, e_acc};
return {std::move(element)};
};
auto find_edge = [](const VertexAccessor &v, const EdgeTypeId &e) -> std::optional<EdgeAccessor> {
auto in = v.InEdges(view, {e});
MG_ASSERT(in.HasValue());
for (auto &edge : in.GetValue()) {
if (edge.EdgeType() == e) {
return edge;
}
}
auto out = v.OutEdges(view, {e});
MG_ASSERT(out.HasValue());
for (auto &edge : out.GetValue()) {
if (edge.EdgeType() == e) {
return edge;
}
}
return std::nullopt;
};
std::vector<GetPropElement> elements;
for (const auto &[vertex, maybe_edge] : req.vertices_and_edges) {
const auto &[label, pk_v] = vertex;
auto pk = ConvertPropertyVector(pk_v);
auto v_acc = dba.FindVertex(pk, view);
if (!v_acc) {
return msgs::GetPropertiesResponse{.result = msgs::GetPropertiesResponse::OUT_OF_SHARD_RANGE};
}
std::optional<EdgeAccessor> e_acc;
if (maybe_edge) {
e_acc = find_edge(*v_acc, *maybe_edge);
if (!e_acc) {
return msgs::GetPropertiesResponse{.result = msgs::GetPropertiesResponse::OUT_OF_SHARD_RANGE};
}
}
const auto *symbol = (maybe_edge) ? expr::identifier_edge_symbol : expr::identifier_node_symbol;
if (req.filter && !FilterOnVertex(dba, *v_acc, {*req.filter}, symbol, e_acc)) {
continue;
}
std::optional<GetPropElement> collected_properties;
collected_properties = collect_props(*v_acc, req.property_ids, view, e_acc);
if (!collected_properties) {
return msgs::GetPropertiesResponse{.result = msgs::GetPropertiesResponse::FAILURE};
}
if (collected_properties->ids.empty()) {
continue;
}
elements.push_back(std::move(*collected_properties));
}
if (!req.order_by.empty()) {
elements = OrderByElements(dba, req.order_by, std::move(elements));
}
std::vector<msgs::GetPropertiesResultRow> results;
results.reserve(elements.size());
const auto has_expr_to_evaluate = !req.expressions.empty();
size_t limit = elements.size();
if (req.limit && *req.limit < elements.size()) {
limit = *req.limit;
}
for (size_t index = 0; index != limit; ++index) {
auto &element = elements.at(index);
const auto id = element.vertex_acc.Id(view).GetValue();
std::optional<EdgeTypeId> e_type =
(element.edge_acc) ? std::make_optional(element.edge_acc->EdgeType()) : std::nullopt;
msgs::VertexId v_id{msgs::Label{id.primary_label}, ConvertValueVector(id.primary_key)};
results.push_back(msgs::GetPropertiesResultRow{
.vertex_and_edge = {.vertex = std::move(v_id), .edge = e_type},
.properies_and_ids = {
.ids = std::move(element.ids),
.properties = ConvertToValueVectorFromTypedValueVector(std::move(element.properties_order_by))}});
if (has_expr_to_evaluate) {
auto expression_results = ConvertToValueVectorFromTypedValueVector(
EvaluateVertexExpressions(dba, element.vertex_acc, req.expressions, expr::identifier_node_symbol));
results.back().evaluated_expressions = std::move(expression_results);
}
}
return msgs::GetPropertiesResponse{std::move(results), msgs::GetPropertiesResponse::SUCCESS};
}
// TODO(kostasrim) Handle edges
} // namespace memgraph::storage::v3

View File

@ -446,6 +446,56 @@ std::tuple<size_t, std::optional<msgs::VertexId>> AttemptToScanAllWithExpression
}
}
msgs::GetPropertiesResponse AttemptToGetProperties(ShardClient &client, std::vector<PropertyId> properties,
std::vector<msgs::VertexId> vertices,
std::vector<msgs::EdgeTypeId> edges,
std::optional<size_t> limit = std::nullopt,
std::optional<uint64_t> filter_prop = std::nullopt,
bool edge = false,
std::optional<std::string> order_by = std::nullopt) {
msgs::GetPropertiesRequest req{};
req.transaction_id.logical_id = GetTransactionId();
req.property_ids = std::move(properties);
if (filter_prop) {
std::string filter_expr = (!edge) ? "MG_SYMBOL_NODE.prop1 >= " : "MG_SYMBOL_EDGE.e_prop = ";
filter_expr += std::to_string(*filter_prop);
req.filter = std::make_optional(std::move(filter_expr));
}
if (order_by) {
std::string filter_expr = (!edge) ? "MG_SYMBOL_NODE." : "MG_SYMBOL_EDGE.";
filter_expr += *order_by;
msgs::OrderBy order_by{.expression = {std::move(filter_expr)}, .direction = msgs::OrderingDirection::DESCENDING};
std::vector<msgs::OrderBy> request_order_by;
request_order_by.push_back(std::move(order_by));
req.order_by = std::move(request_order_by);
}
if (limit) {
req.limit = limit;
}
req.expressions = {std::string("5 = 5")};
std::vector<msgs::VertexAndEdgeId> req_v;
for (auto &v : vertices) {
req_v.push_back(msgs::VertexAndEdgeId{.vertex = std::move(v)});
}
for (auto index = 0; index != edges.size(); ++index) {
req_v[index].edge = edges[index];
}
req.vertices_and_edges = std::move(req_v);
while (true) {
auto read_res = client.SendReadRequest(req);
if (read_res.HasError()) {
continue;
}
auto write_response_result = read_res.GetValue();
auto write_response = std::get<msgs::GetPropertiesResponse>(write_response_result);
return write_response;
}
}
void AttemptToScanAllWithOrderByOnPrimaryProperty(ShardClient &client, msgs::VertexId start_id, uint64_t batch_limit) {
msgs::ScanVerticesRequest scan_req;
scan_req.batch_limit = batch_limit;
@ -1064,6 +1114,193 @@ void TestExpandOneGraphTwo(ShardClient &client) {
}
}
void TestGetProperties(ShardClient &client) {
const auto unique_prop_val_1 = GetUniqueInteger();
const auto unique_prop_val_2 = GetUniqueInteger();
const auto unique_prop_val_3 = GetUniqueInteger();
const auto unique_prop_val_4 = GetUniqueInteger();
const auto unique_prop_val_5 = GetUniqueInteger();
MG_ASSERT(AttemptToCreateVertex(client, unique_prop_val_1));
MG_ASSERT(AttemptToCreateVertex(client, unique_prop_val_2));
MG_ASSERT(AttemptToCreateVertex(client, unique_prop_val_3));
MG_ASSERT(AttemptToCreateVertex(client, unique_prop_val_4));
MG_ASSERT(AttemptToCreateVertex(client, unique_prop_val_5));
const msgs::Label prim_label = {.id = get_primary_label()};
const msgs::PrimaryKey prim_key = {msgs::Value(static_cast<int64_t>(unique_prop_val_1))};
const msgs::VertexId v_id = {prim_label, prim_key};
const msgs::PrimaryKey prim_key_2 = {msgs::Value(static_cast<int64_t>(unique_prop_val_2))};
const msgs::VertexId v_id_2 = {prim_label, prim_key_2};
const msgs::PrimaryKey prim_key_3 = {msgs::Value(static_cast<int64_t>(unique_prop_val_3))};
const msgs::VertexId v_id_3 = {prim_label, prim_key_3};
const msgs::PrimaryKey prim_key_4 = {msgs::Value(static_cast<int64_t>(unique_prop_val_4))};
const msgs::VertexId v_id_4 = {prim_label, prim_key_4};
const msgs::PrimaryKey prim_key_5 = {msgs::Value(static_cast<int64_t>(unique_prop_val_5))};
const msgs::VertexId v_id_5 = {prim_label, prim_key_5};
const auto prop_id_2 = PropertyId::FromUint(2);
const auto prop_id_4 = PropertyId::FromUint(4);
const auto prop_id_5 = PropertyId::FromUint(5);
// Vertices
{
// No properties
const auto result = AttemptToGetProperties(client, {}, {v_id, v_id_2}, {}, std::nullopt, unique_prop_val_2);
MG_ASSERT(result.result == msgs::GetPropertiesResponse::SUCCESS);
MG_ASSERT(result.result_row.empty());
}
{
// All properties
const auto result = AttemptToGetProperties(client, {prop_id_2, prop_id_4, prop_id_5}, {v_id, v_id_2, v_id_3}, {});
MG_ASSERT(result.result == msgs::GetPropertiesResponse::SUCCESS);
MG_ASSERT(!result.result_row.empty());
MG_ASSERT(result.result_row.size() == 3);
for (const auto &elem : result.result_row) {
MG_ASSERT(elem.properies_and_ids.ids.size() == 3);
MG_ASSERT(elem.properies_and_ids.properties.size() == 3);
}
}
{
// Two properties from two vertices with a filter on unique_prop_5
const auto result = AttemptToGetProperties(client, {prop_id_2, prop_id_4}, {v_id, v_id_2, v_id_5}, {}, std::nullopt,
unique_prop_val_5);
MG_ASSERT(result.result == msgs::GetPropertiesResponse::SUCCESS);
MG_ASSERT(!result.result_row.empty());
MG_ASSERT(result.result_row.size() == 1);
}
{
// One property from three vertices.
const auto result = AttemptToGetProperties(client, {prop_id_2}, {v_id, v_id_2, v_id_3}, {});
MG_ASSERT(result.result == msgs::GetPropertiesResponse::SUCCESS);
MG_ASSERT(!result.result_row.empty());
MG_ASSERT(result.result_row.size() == 3);
MG_ASSERT(result.result_row[0].properies_and_ids.ids.size() == 1);
MG_ASSERT(result.result_row[1].properies_and_ids.ids.size() == 1);
MG_ASSERT(result.result_row[2].properies_and_ids.ids.size() == 1);
}
{
// Same as before but with limit of 1 row
const auto result =
AttemptToGetProperties(client, {prop_id_2}, {v_id, v_id_2, v_id_3}, {}, std::make_optional<size_t>(1));
MG_ASSERT(result.result == msgs::GetPropertiesResponse::SUCCESS);
MG_ASSERT(!result.result_row.empty());
MG_ASSERT(result.result_row.size() == 1);
}
{
// Same as before but with a limit greater than the elements returned
const auto result =
AttemptToGetProperties(client, {prop_id_2}, {v_id, v_id_2, v_id_3}, {}, std::make_optional<size_t>(5));
MG_ASSERT(result.result == msgs::GetPropertiesResponse::SUCCESS);
MG_ASSERT(!result.result_row.empty());
MG_ASSERT(result.result_row.size() == 3);
}
{
// Order by on `prop1` (descending)
const auto result = AttemptToGetProperties(client, {prop_id_2}, {v_id, v_id_2, v_id_3}, {}, std::nullopt,
std::nullopt, false, "prop1");
MG_ASSERT(result.result == msgs::GetPropertiesResponse::SUCCESS);
MG_ASSERT(!result.result_row.empty());
MG_ASSERT(result.result_row.size() == 3);
MG_ASSERT(result.result_row[0].vertex_and_edge.vertex == v_id_3);
MG_ASSERT(result.result_row[1].vertex_and_edge.vertex == v_id_2);
MG_ASSERT(result.result_row[2].vertex_and_edge.vertex == v_id);
}
{
// Order by and filter on >= unique_prop_val_3 && assert result row data members
const auto result = AttemptToGetProperties(client, {prop_id_2}, {v_id, v_id_2, v_id_3, v_id_4, v_id_5}, {},
std::nullopt, unique_prop_val_3, false, "prop1");
MG_ASSERT(result.result == msgs::GetPropertiesResponse::SUCCESS);
MG_ASSERT(!result.result_row.empty());
MG_ASSERT(result.result_row.size() == 3);
MG_ASSERT(result.result_row[0].vertex_and_edge.vertex == v_id_5);
MG_ASSERT(result.result_row[0].properies_and_ids.properties.size() == 1);
MG_ASSERT(result.result_row[0].properies_and_ids.properties.front() == prim_key_5.front());
MG_ASSERT(result.result_row[0].properies_and_ids.ids.size() == 1);
MG_ASSERT(result.result_row[0].properies_and_ids.ids.front() == prop_id_2);
MG_ASSERT(result.result_row[0].evaluated_expressions.size() == 1);
MG_ASSERT(result.result_row[0].evaluated_expressions.front() == msgs::Value(true));
MG_ASSERT(result.result_row[1].vertex_and_edge.vertex == v_id_4);
MG_ASSERT(result.result_row[1].properies_and_ids.properties.size() == 1);
MG_ASSERT(result.result_row[1].properies_and_ids.properties.front() == prim_key_4.front());
MG_ASSERT(result.result_row[1].properies_and_ids.ids.size() == 1);
MG_ASSERT(result.result_row[1].properies_and_ids.ids.front() == prop_id_2);
MG_ASSERT(result.result_row[1].evaluated_expressions.size() == 1);
MG_ASSERT(result.result_row[1].evaluated_expressions.front() == msgs::Value(true));
MG_ASSERT(result.result_row[2].vertex_and_edge.vertex == v_id_3);
MG_ASSERT(result.result_row[2].properies_and_ids.properties.size() == 1);
MG_ASSERT(result.result_row[2].properies_and_ids.properties.front() == prim_key_3.front());
MG_ASSERT(result.result_row[2].properies_and_ids.ids.size() == 1);
MG_ASSERT(result.result_row[2].properies_and_ids.ids.front() == prop_id_2);
MG_ASSERT(result.result_row[2].evaluated_expressions.size() == 1);
MG_ASSERT(result.result_row[2].evaluated_expressions.front() == msgs::Value(true));
}
// Edges
const auto edge_gid = GetUniqueInteger();
const auto edge_type_id = EdgeTypeId::FromUint(GetUniqueInteger());
const auto unique_edge_prop_id = 7;
const auto edge_prop_val = GetUniqueInteger();
MG_ASSERT(AttemptToAddEdgeWithProperties(client, unique_prop_val_1, unique_prop_val_2, edge_gid, unique_edge_prop_id,
edge_prop_val, {edge_type_id}));
const auto edge_gid_2 = GetUniqueInteger();
const auto edge_prop_val_2 = GetUniqueInteger();
MG_ASSERT(AttemptToAddEdgeWithProperties(client, unique_prop_val_3, unique_prop_val_4, edge_gid_2,
unique_edge_prop_id, edge_prop_val_2, {edge_type_id}));
const auto edge_prop_id = PropertyId::FromUint(unique_edge_prop_id);
// no properties
{
const auto result = AttemptToGetProperties(client, {}, {v_id_2, v_id_3}, {edge_type_id, edge_type_id});
MG_ASSERT(result.result == msgs::GetPropertiesResponse::SUCCESS);
MG_ASSERT(result.result_row.empty());
}
// properties for two vertices
{
const auto result = AttemptToGetProperties(client, {edge_prop_id}, {v_id_2, v_id_3}, {edge_type_id, edge_type_id});
MG_ASSERT(result.result == msgs::GetPropertiesResponse::SUCCESS);
MG_ASSERT(!result.result_row.empty());
MG_ASSERT(result.result_row.size() == 2);
}
// filter
{
const auto result = AttemptToGetProperties(client, {edge_prop_id}, {v_id_2, v_id_3}, {edge_type_id, edge_type_id},
{}, {edge_prop_val}, true);
MG_ASSERT(result.result == msgs::GetPropertiesResponse::SUCCESS);
MG_ASSERT(!result.result_row.empty());
MG_ASSERT(result.result_row.size() == 1);
MG_ASSERT(result.result_row.front().vertex_and_edge.edge);
MG_ASSERT(result.result_row.front().vertex_and_edge.edge.value() == edge_type_id);
MG_ASSERT(result.result_row.front().properies_and_ids.properties.size() == 1);
MG_ASSERT(result.result_row.front().properies_and_ids.properties.front() ==
msgs::Value(static_cast<int64_t>(edge_prop_val)));
}
// Order by
{
const auto result = AttemptToGetProperties(client, {edge_prop_id}, {v_id_2, v_id_3}, {edge_type_id, edge_type_id},
{}, {}, true, "e_prop");
MG_ASSERT(result.result == msgs::GetPropertiesResponse::SUCCESS);
MG_ASSERT(!result.result_row.empty());
MG_ASSERT(result.result_row.size() == 2);
MG_ASSERT(result.result_row[0].vertex_and_edge.vertex == v_id_3);
MG_ASSERT(result.result_row[0].vertex_and_edge.edge);
MG_ASSERT(result.result_row[0].vertex_and_edge.edge.value() == edge_type_id);
MG_ASSERT(result.result_row[0].properies_and_ids.properties.size() == 1);
MG_ASSERT(result.result_row[0].properies_and_ids.properties.front() ==
msgs::Value(static_cast<int64_t>(edge_prop_val_2)));
MG_ASSERT(result.result_row[0].evaluated_expressions.size() == 1);
MG_ASSERT(result.result_row[0].evaluated_expressions.front() == msgs::Value(true));
MG_ASSERT(result.result_row[1].vertex_and_edge.vertex == v_id_2);
MG_ASSERT(result.result_row[1].vertex_and_edge.edge);
MG_ASSERT(result.result_row[1].vertex_and_edge.edge.value() == edge_type_id);
MG_ASSERT(result.result_row[1].properies_and_ids.properties.size() == 1);
MG_ASSERT(result.result_row[1].properies_and_ids.properties.front() ==
msgs::Value(static_cast<int64_t>(edge_prop_val)));
MG_ASSERT(result.result_row[1].evaluated_expressions.size() == 1);
MG_ASSERT(result.result_row[1].evaluated_expressions.front() == msgs::Value(true));
}
}
} // namespace
int TestMessages() {
@ -1102,9 +1339,12 @@ int TestMessages() {
auto shard_ptr2 = std::make_unique<Shard>(get_primary_label(), min_prim_key, max_prim_key, schema_prop);
auto shard_ptr3 = std::make_unique<Shard>(get_primary_label(), min_prim_key, max_prim_key, schema_prop);
shard_ptr1->StoreMapping({{1, "label"}, {2, "prop1"}, {3, "label1"}, {4, "prop2"}, {5, "prop3"}, {6, "prop4"}});
shard_ptr2->StoreMapping({{1, "label"}, {2, "prop1"}, {3, "label1"}, {4, "prop2"}, {5, "prop3"}, {6, "prop4"}});
shard_ptr3->StoreMapping({{1, "label"}, {2, "prop1"}, {3, "label1"}, {4, "prop2"}, {5, "prop3"}, {6, "prop4"}});
shard_ptr1->StoreMapping(
{{1, "label"}, {2, "prop1"}, {3, "label1"}, {4, "prop2"}, {5, "prop3"}, {6, "prop4"}, {7, "e_prop"}});
shard_ptr2->StoreMapping(
{{1, "label"}, {2, "prop1"}, {3, "label1"}, {4, "prop2"}, {5, "prop3"}, {6, "prop4"}, {7, "e_prop"}});
shard_ptr3->StoreMapping(
{{1, "label"}, {2, "prop1"}, {3, "label1"}, {4, "prop2"}, {5, "prop3"}, {6, "prop4"}, {7, "e_prop"}});
std::vector<Address> address_for_1{shard_server_2_address, shard_server_3_address};
std::vector<Address> address_for_2{shard_server_1_address, shard_server_3_address};
@ -1145,6 +1385,8 @@ int TestMessages() {
TestExpandOneGraphOne(client);
TestExpandOneGraphTwo(client);
// GetProperties tests
TestGetProperties(client);
simulator.ShutDown();
SimulatorStats stats = simulator.Stats();