From 9ec72bd96985bc3ecea5031f18dd90292daa5bc3 Mon Sep 17 00:00:00 2001 From: Kostas Kyrimis Date: Wed, 16 Nov 2022 18:41:22 +0200 Subject: [PATCH] Add GetProperties shard handler and tests --- src/query/v2/requests.hpp | 40 +++-- src/storage/v3/request_helper.cpp | 62 +++++++- src/storage/v3/request_helper.hpp | 11 ++ src/storage/v3/shard_rsm.cpp | 138 ++++++++++++++++- tests/simulation/shard_rsm.cpp | 248 +++++++++++++++++++++++++++++- 5 files changed, 474 insertions(+), 25 deletions(-) diff --git a/src/query/v2/requests.hpp b/src/query/v2/requests.hpp index 2ea4efb57..4c9280848 100644 --- a/src/query/v2/requests.hpp +++ b/src/query/v2/requests.hpp @@ -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 results; }; -using VertexOrEdgeIds = std::variant; +struct VertexAndEdgeId { + VertexId vertex; + std::optional edge; +}; struct GetPropertiesRequest { Hlc transaction_id; - // Shouldn't contain mixed vertex and edge ids - VertexOrEdgeIds vertex_or_edge_ids; + std::vector vertices_and_edges; + std::vector property_ids; - std::vector expressions; - bool only_unique = false; - std::optional> order_by; + std::vector expressions; + + std::vector order_by; std::optional limit; - std::optional filter; + + // Return only the properties of the vertices or edges that the filter predicate + // evaluates to true + std::optional filter; +}; + +struct PropIdValue { + std::vector ids; + std::vector properties; +}; + +struct GetPropertiesResultRow { + VertexAndEdgeId vertex_and_edge; + + PropIdValue properies_and_ids; + std::vector evaluated_expressions; }; struct GetPropertiesResponse { - bool success; + std::vector 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 }; diff --git a/src/storage/v3/request_helper.cpp b/src/storage/v3/request_helper.cpp index bb1c8bca4..96170dccf 100644 --- a/src/storage/v3/request_helper.cpp +++ b/src/storage/v3/request_helper.cpp @@ -11,6 +11,7 @@ #include "storage/v3/request_helper.hpp" +#include #include #include "pretty_print_ast_to_original_expression.hpp" @@ -43,19 +44,74 @@ std::vector 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 OrderByElements(DbAccessor &dba, std::vector &order_by, + std::vector &&vertices) { + std::vector 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 properties_order_by; + VertexAccessor vertex_acc; + GetPropElement *original_element; + }; + + std::vector ordered; + auto compare_typed_values = TypedValueVectorCompare(ordering); + for (auto &vertex : vertices) { + std::vector 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 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 &start_ids, const View view) { auto it = vertex_iterable.begin(); diff --git a/src/storage/v3/request_helper.hpp b/src/storage/v3/request_helper.hpp index 24ed40f8c..f98f18cd3 100644 --- a/src/storage/v3/request_helper.hpp +++ b/src/storage/v3/request_helper.hpp @@ -12,6 +12,7 @@ #include #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 properties_order_by; + std::vector ids; + VertexAccessor vertex_acc; + std::optional edge_acc; +}; + std::vector OrderByElements(Shard::Accessor &acc, DbAccessor &dba, VerticesIterable &vertices_iterable, std::vector &order_bys); +std::vector OrderByElements(DbAccessor &dba, std::vector &order_bys, + std::vector &&vertices); + VerticesIterable::Iterator GetStartVertexIterator(VerticesIterable &vertex_iterable, const std::vector &start_ids, View view); diff --git a/src/storage/v3/shard_rsm.cpp b/src/storage/v3/shard_rsm.cpp index f288e5e27..4036bbd80 100644 --- a/src/storage/v3/shard_rsm.cpp +++ b/src/storage/v3/shard_rsm.cpp @@ -15,8 +15,10 @@ #include #include #include +#include #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> CollectAllPropertiesFromAccessor(cons } bool FilterOnVertex(DbAccessor &dba, const storage::v3::VertexAccessor &v_acc, const std::vector &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 &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 &props, View view, + const std::optional &e_acc) mutable -> std::optional { + std::vector properties; + std::vector ids; + for (const auto &prop : props) { + Result 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(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 { + 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 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 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 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 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 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 diff --git a/tests/simulation/shard_rsm.cpp b/tests/simulation/shard_rsm.cpp index 64d0a0861..f2a90262f 100644 --- a/tests/simulation/shard_rsm.cpp +++ b/tests/simulation/shard_rsm.cpp @@ -446,6 +446,56 @@ std::tuple> AttemptToScanAllWithExpression } } +msgs::GetPropertiesResponse AttemptToGetProperties(ShardClient &client, std::vector properties, + std::vector vertices, + std::vector edges, + std::optional limit = std::nullopt, + std::optional filter_prop = std::nullopt, + bool edge = false, + std::optional 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 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 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(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(unique_prop_val_1))}; + const msgs::VertexId v_id = {prim_label, prim_key}; + const msgs::PrimaryKey prim_key_2 = {msgs::Value(static_cast(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(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(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(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(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(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(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(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(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(get_primary_label(), min_prim_key, max_prim_key, schema_prop); auto shard_ptr3 = std::make_unique(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_for_1{shard_server_2_address, shard_server_3_address}; std::vector
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();