Prototype suggested changes and polish PR
This commit is contained in:
parent
07a8ac0db8
commit
9621532d3d
src
tests/simulation
@ -368,16 +368,12 @@ struct ScanVerticesResponse {
|
||||
std::vector<ScanResultRow> results;
|
||||
};
|
||||
|
||||
struct VertexAndEdgeId {
|
||||
VertexId vertex;
|
||||
std::optional<EdgeTypeId> edge;
|
||||
};
|
||||
|
||||
struct GetPropertiesRequest {
|
||||
Hlc transaction_id;
|
||||
std::vector<VertexAndEdgeId> vertices_and_edges;
|
||||
std::vector<VertexId> vertex_ids;
|
||||
std::vector<std::pair<VertexId, EdgeId>> vertices_and_edges;
|
||||
|
||||
std::vector<PropertyId> property_ids;
|
||||
std::optional<std::vector<PropertyId>> property_ids;
|
||||
std::vector<std::string> expressions;
|
||||
|
||||
std::vector<OrderBy> order_by;
|
||||
@ -388,22 +384,16 @@ struct GetPropertiesRequest {
|
||||
std::optional<std::string> filter;
|
||||
};
|
||||
|
||||
struct PropIdValue {
|
||||
std::vector<PropertyId> ids;
|
||||
std::vector<Value> properties;
|
||||
};
|
||||
|
||||
struct GetPropertiesResultRow {
|
||||
VertexAndEdgeId vertex_and_edge;
|
||||
VertexId vertex;
|
||||
std::optional<EdgeId> edge;
|
||||
|
||||
PropIdValue properies_and_ids;
|
||||
std::vector<std::pair<PropertyId, Value>> props;
|
||||
std::vector<Value> evaluated_expressions;
|
||||
};
|
||||
|
||||
struct GetPropertiesResponse {
|
||||
std::vector<GetPropertiesResultRow> result_row;
|
||||
enum RequestResult : uint16_t { OUT_OF_SHARD_RANGE, SUCCESS, FAILURE };
|
||||
RequestResult result;
|
||||
std::optional<ShardError> error;
|
||||
};
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
|
||||
#include "pretty_print_ast_to_original_expression.hpp"
|
||||
#include "storage/v3/bindings/db_accessor.hpp"
|
||||
#include "storage/v3/bindings/pretty_print_ast_to_original_expression.hpp"
|
||||
#include "storage/v3/expr.hpp"
|
||||
@ -221,30 +222,39 @@ std::vector<TypedValue> EvaluateVertexExpressions(DbAccessor &dba, const VertexA
|
||||
return evaluated_expressions;
|
||||
}
|
||||
|
||||
std::vector<TypedValue> EvaluateEdgeExpressions(DbAccessor &dba, const VertexAccessor &v_acc, const EdgeAccessor &e_acc,
|
||||
const std::vector<std::string> &expressions) {
|
||||
std::vector<TypedValue> evaluated_expressions;
|
||||
evaluated_expressions.reserve(expressions.size());
|
||||
|
||||
std::transform(expressions.begin(), expressions.end(), std::back_inserter(evaluated_expressions),
|
||||
[&dba, &v_acc, &e_acc](const auto &expression) {
|
||||
return ComputeExpression(dba, v_acc, e_acc, expression, expr::identifier_node_symbol,
|
||||
expr::identifier_edge_symbol);
|
||||
});
|
||||
|
||||
return evaluated_expressions;
|
||||
}
|
||||
|
||||
ShardResult<std::map<PropertyId, Value>> CollectAllPropertiesFromAccessor(const VertexAccessor &acc, View view,
|
||||
const Schemas::Schema &schema) {
|
||||
std::map<PropertyId, Value> ret;
|
||||
auto props = acc.Properties(view);
|
||||
if (props.HasError()) {
|
||||
spdlog::debug("Encountered an error while trying to get vertex properties.");
|
||||
return props.GetError();
|
||||
auto ret = impl::CollectAllPropertiesImpl<VertexAccessor>(acc, view);
|
||||
if (ret.HasError()) {
|
||||
return ret.GetError();
|
||||
}
|
||||
|
||||
auto &properties = props.GetValue();
|
||||
std::transform(properties.begin(), properties.end(), std::inserter(ret, ret.begin()),
|
||||
[](std::pair<const PropertyId, PropertyValue> &pair) {
|
||||
return std::make_pair(pair.first, FromPropertyValueToValue(std::move(pair.second)));
|
||||
});
|
||||
properties.clear();
|
||||
|
||||
auto pks = PrimaryKeysFromAccessor(acc, view, schema);
|
||||
if (pks) {
|
||||
ret.merge(*pks);
|
||||
ret.GetValue().merge(*pks);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ShardResult<std::map<PropertyId, Value>> CollectAllPropertiesFromAccessor(const VertexAccessor &acc, View view) {
|
||||
return impl::CollectAllPropertiesImpl(acc, view);
|
||||
}
|
||||
|
||||
EdgeUniquenessFunction InitializeEdgeUniquenessFunction(bool only_unique_neighbor_rows) {
|
||||
// Functions to select connecting edges based on uniquness
|
||||
EdgeUniquenessFunction maybe_filter_based_on_edge_uniquness;
|
||||
@ -351,15 +361,19 @@ EdgeFiller InitializeEdgeFillerFunction(const msgs::ExpandOneRequest &req) {
|
||||
return edge_filler;
|
||||
}
|
||||
|
||||
bool FilterOnVertex(DbAccessor &dba, const storage::v3::VertexAccessor &v_acc, const std::vector<std::string> &filters,
|
||||
const std::string_view node_name, const std::optional<EdgeAccessor> &e_acc) {
|
||||
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, "");
|
||||
}
|
||||
bool FilterOnVertex(DbAccessor &dba, const storage::v3::VertexAccessor &v_acc,
|
||||
const std::vector<std::string> &filters) {
|
||||
return std::ranges::all_of(filters, [&dba, &v_acc](const auto &filter_expr) {
|
||||
const auto result = ComputeExpression(dba, v_acc, std::nullopt, filter_expr, expr::identifier_node_symbol, "");
|
||||
return result.IsBool() && result.ValueBool();
|
||||
});
|
||||
}
|
||||
|
||||
bool FilterOnEdge(DbAccessor &dba, const storage::v3::VertexAccessor &v_acc, const EdgeAccessor &e_acc,
|
||||
const std::vector<std::string> &filters) {
|
||||
return std::ranges::all_of(filters, [&dba, &v_acc, &e_acc](const auto &filter_expr) {
|
||||
const auto result =
|
||||
ComputeExpression(dba, v_acc, e_acc, filter_expr, expr::identifier_node_symbol, expr::identifier_edge_symbol);
|
||||
return result.IsBool() && result.ValueBool();
|
||||
});
|
||||
}
|
||||
@ -444,61 +458,6 @@ ShardResult<msgs::ExpandOneResultRow> GetExpandOneResult(
|
||||
return result_row;
|
||||
}
|
||||
|
||||
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> &primary_key, const View view) {
|
||||
auto it = vertex_iterable.begin();
|
||||
@ -584,4 +543,36 @@ std::vector<Element<EdgeAccessor>> OrderByEdges(DbAccessor &dba, std::vector<Edg
|
||||
return ordered;
|
||||
}
|
||||
|
||||
std::vector<Element<std::pair<VertexAccessor, EdgeAccessor>>> OrderByEdges(
|
||||
DbAccessor &dba, std::vector<EdgeAccessor> &iterable, std::vector<msgs::OrderBy> &order_by_edges,
|
||||
const std::vector<VertexAccessor> &vertex_acc) {
|
||||
MG_ASSERT(vertex_acc.size() == iterable.size());
|
||||
std::vector<Ordering> ordering;
|
||||
ordering.reserve(order_by_edges.size());
|
||||
std::transform(order_by_edges.begin(), order_by_edges.end(), std::back_inserter(ordering),
|
||||
[](const auto &order_by) { return ConvertMsgsOrderByToOrdering(order_by.direction); });
|
||||
|
||||
std::vector<Element<std::pair<VertexAccessor, EdgeAccessor>>> ordered;
|
||||
VertexAccessor current = vertex_acc.front();
|
||||
size_t id = 0;
|
||||
for (auto it = iterable.begin(); it != iterable.end(); it++, id++) {
|
||||
current = vertex_acc[id];
|
||||
std::vector<TypedValue> properties_order_by;
|
||||
properties_order_by.reserve(order_by_edges.size());
|
||||
std::transform(order_by_edges.begin(), order_by_edges.end(), std::back_inserter(properties_order_by),
|
||||
[&dba, it, current](const auto &order_by) {
|
||||
return ComputeExpression(dba, current, *it, order_by.expression.expression,
|
||||
expr::identifier_node_symbol, expr::identifier_edge_symbol);
|
||||
});
|
||||
|
||||
ordered.push_back({std::move(properties_order_by), {current, *it}});
|
||||
}
|
||||
|
||||
auto compare_typed_values = TypedValueVectorCompare(ordering);
|
||||
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;
|
||||
}
|
||||
|
||||
} // namespace memgraph::storage::v3
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "storage/v3/edge_accessor.hpp"
|
||||
#include "storage/v3/expr.hpp"
|
||||
#include "storage/v3/shard.hpp"
|
||||
#include "storage/v3/value_conversions.hpp"
|
||||
#include "storage/v3/vertex_accessor.hpp"
|
||||
#include "utils/template_utils.hpp"
|
||||
|
||||
@ -31,7 +32,7 @@ using EdgeFiller =
|
||||
using msgs::Value;
|
||||
|
||||
template <typename T>
|
||||
concept ObjectAccessor = utils::SameAsAnyOf<T, VertexAccessor, EdgeAccessor>;
|
||||
concept ObjectAccessor = utils::SameAsAnyOf<T, VertexAccessor, EdgeAccessor, std::pair<VertexAccessor, EdgeAccessor>>;
|
||||
|
||||
inline bool TypedValueCompare(const TypedValue &a, const TypedValue &b) {
|
||||
// in ordering null comes after everything else
|
||||
@ -131,13 +132,6 @@ struct Element {
|
||||
TObjectAccessor object_acc;
|
||||
};
|
||||
|
||||
struct GetPropElement {
|
||||
std::vector<TypedValue> properties_order_by;
|
||||
std::vector<PropertyId> ids;
|
||||
VertexAccessor vertex_acc;
|
||||
std::optional<EdgeAccessor> edge_acc;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
concept VerticesIt = utils::SameAsAnyOf<T, VerticesIterable, std::vector<VertexAccessor>>;
|
||||
|
||||
@ -170,12 +164,16 @@ std::vector<Element<VertexAccessor>> OrderByVertices(DbAccessor &dba, TIterable
|
||||
return ordered;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
concept EdgeObjectAccessor = utils::SameAsAnyOf<T, EdgeAccessor, std::pair<VertexAccessor, EdgeAccessor>>;
|
||||
|
||||
std::vector<Element<EdgeAccessor>> OrderByEdges(DbAccessor &dba, std::vector<EdgeAccessor> &iterable,
|
||||
std::vector<msgs::OrderBy> &order_by_edges,
|
||||
const VertexAccessor &vertex_acc);
|
||||
|
||||
std::vector<GetPropElement> OrderByElements(DbAccessor &dba, std::vector<msgs::OrderBy> &order_bys,
|
||||
std::vector<GetPropElement> &&vertices);
|
||||
std::vector<Element<std::pair<VertexAccessor, EdgeAccessor>>> OrderByEdges(
|
||||
DbAccessor &dba, std::vector<EdgeAccessor> &iterable, std::vector<msgs::OrderBy> &order_by_edges,
|
||||
const std::vector<VertexAccessor> &vertex_acc);
|
||||
|
||||
VerticesIterable::Iterator GetStartVertexIterator(VerticesIterable &vertex_iterable,
|
||||
const std::vector<PropertyValue> &primary_key, View view);
|
||||
@ -187,19 +185,65 @@ std::vector<Element<VertexAccessor>>::const_iterator GetStartOrderedElementsIter
|
||||
std::array<std::vector<EdgeAccessor>, 2> GetEdgesFromVertex(const VertexAccessor &vertex_accessor,
|
||||
msgs::EdgeDirection direction);
|
||||
|
||||
bool FilterOnVertex(DbAccessor &dba, const storage::v3::VertexAccessor &v_acc, const std::vector<std::string> &filters,
|
||||
const std::string_view node_name, const std::optional<EdgeAccessor> &e_acc = std::nullopt);
|
||||
bool FilterOnVertex(DbAccessor &dba, const storage::v3::VertexAccessor &v_acc, const std::vector<std::string> &filters);
|
||||
|
||||
bool FilterOnEdge(DbAccessor &dba, const storage::v3::VertexAccessor &v_acc, const EdgeAccessor &e_acc,
|
||||
const std::vector<std::string> &filters);
|
||||
|
||||
std::vector<TypedValue> EvaluateVertexExpressions(DbAccessor &dba, const VertexAccessor &v_acc,
|
||||
const std::vector<std::string> &expressions,
|
||||
std::string_view node_name);
|
||||
|
||||
ShardResult<std::map<PropertyId, Value>> CollectSpecificPropertiesFromAccessor(const VertexAccessor &acc,
|
||||
std::vector<TypedValue> EvaluateEdgeExpressions(DbAccessor &dba, const VertexAccessor &v_acc, const EdgeAccessor &e_acc,
|
||||
const std::vector<std::string> &expressions);
|
||||
|
||||
template <typename T>
|
||||
concept TAccessor = utils::SameAsAnyOf<T, VertexAccessor, EdgeAccessor>;
|
||||
|
||||
template <typename TAccessor>
|
||||
ShardResult<std::map<PropertyId, Value>> CollectSpecificPropertiesFromAccessor(const TAccessor &acc,
|
||||
const std::vector<PropertyId> &props,
|
||||
View view);
|
||||
View view) {
|
||||
std::map<PropertyId, Value> ret;
|
||||
|
||||
for (const auto &prop : props) {
|
||||
auto result = acc.GetProperty(prop, view);
|
||||
if (result.HasError()) {
|
||||
spdlog::debug("Encountered an Error while trying to get a vertex property.");
|
||||
return result.GetError();
|
||||
}
|
||||
auto &value = result.GetValue();
|
||||
ret.emplace(std::make_pair(prop, FromPropertyValueToValue(std::move(value))));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ShardResult<std::map<PropertyId, Value>> CollectAllPropertiesFromAccessor(const VertexAccessor &acc, View view,
|
||||
const Schemas::Schema &schema);
|
||||
namespace impl {
|
||||
template <typename TAccessor>
|
||||
ShardResult<std::map<PropertyId, Value>> CollectAllPropertiesImpl(const TAccessor &acc, View view) {
|
||||
std::map<PropertyId, Value> ret;
|
||||
auto props = acc.Properties(view);
|
||||
if (props.HasError()) {
|
||||
spdlog::debug("Encountered an error while trying to get vertex properties.");
|
||||
return props.GetError();
|
||||
}
|
||||
|
||||
auto &properties = props.GetValue();
|
||||
std::transform(properties.begin(), properties.end(), std::inserter(ret, ret.begin()),
|
||||
[](std::pair<const PropertyId, PropertyValue> &pair) {
|
||||
return std::make_pair(pair.first, conversions::FromPropertyValueToValue(std::move(pair.second)));
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
} // namespace impl
|
||||
|
||||
template <typename TAccessor>
|
||||
ShardResult<std::map<PropertyId, Value>> CollectAllPropertiesFromAccessor(const TAccessor &acc, View view) {
|
||||
return impl::CollectAllPropertiesImpl<TAccessor>(acc, view);
|
||||
}
|
||||
|
||||
EdgeUniquenessFunction InitializeEdgeUniquenessFunction(bool only_unique_neighbor_rows);
|
||||
|
||||
|
@ -10,6 +10,8 @@
|
||||
// licenses/APL.txt.
|
||||
|
||||
#include <algorithm>
|
||||
#include <exception>
|
||||
#include <experimental/source_location>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <optional>
|
||||
@ -19,7 +21,6 @@
|
||||
|
||||
#include "common/errors.hpp"
|
||||
#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"
|
||||
@ -330,7 +331,7 @@ msgs::ReadResponses ShardRsm::HandleRead(msgs::ScanVerticesRequest &&req) {
|
||||
std::vector<Value> expression_results;
|
||||
if (!req.filter_expressions.empty()) {
|
||||
// NOTE - DbAccessor might get removed in the future.
|
||||
const bool eval = FilterOnVertex(dba, vertex, req.filter_expressions, expr::identifier_node_symbol);
|
||||
const bool eval = FilterOnVertex(dba, vertex, req.filter_expressions);
|
||||
if (!eval) {
|
||||
return;
|
||||
}
|
||||
@ -435,7 +436,7 @@ msgs::ReadResponses ShardRsm::HandleRead(msgs::ExpandOneRequest &&req) {
|
||||
}
|
||||
if (!req.filters.empty()) {
|
||||
// NOTE - DbAccessor might get removed in the future.
|
||||
const bool eval = FilterOnVertex(dba, src_vertex_acc_opt.value(), req.filters, expr::identifier_node_symbol);
|
||||
const bool eval = FilterOnVertex(dba, src_vertex_acc_opt.value(), req.filters);
|
||||
if (!eval) {
|
||||
continue;
|
||||
}
|
||||
@ -515,124 +516,184 @@ msgs::WriteResponses ShardRsm::ApplyWrite(msgs::CommitRequest &&req) {
|
||||
};
|
||||
|
||||
msgs::ReadResponses ShardRsm::HandleRead(msgs::GetPropertiesRequest &&req) {
|
||||
if (req.vertices_and_edges.empty()) {
|
||||
return msgs::GetPropertiesResponse{.result = msgs::GetPropertiesResponse::FAILURE};
|
||||
if (!req.vertex_ids.empty() && !req.vertices_and_edges.empty()) {
|
||||
auto error = CreateErrorResponse(
|
||||
{common::ErrorCode::VERTEX_HAS_EDGES, std::experimental::source_location::current()}, req.transaction_id, "");
|
||||
return msgs::GetPropertiesResponse{.error = {}};
|
||||
}
|
||||
|
||||
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) {
|
||||
ShardResult<PropertyValue> result{PropertyValue()};
|
||||
if (e_acc) {
|
||||
result = e_acc->GetProperty(prop, view);
|
||||
} else {
|
||||
result = acc.GetProperty(prop, view);
|
||||
}
|
||||
if (result.HasError() && result.GetError() == common::ErrorCode::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);
|
||||
auto transform_props = [](std::map<PropertyId, Value> &&value) {
|
||||
std::vector<std::pair<PropertyId, Value>> result;
|
||||
result.reserve(value.size());
|
||||
for (auto &[id, val] : value) {
|
||||
result.push_back({id, std::move(val)});
|
||||
}
|
||||
GetPropElement element{std::move(properties), std::move(ids), acc, e_acc};
|
||||
return {std::move(element)};
|
||||
return result;
|
||||
};
|
||||
|
||||
auto find_edge = [](const VertexAccessor &v, const EdgeTypeId &e) -> std::optional<EdgeAccessor> {
|
||||
auto in = v.InEdges(view, {e});
|
||||
auto collect_props = [&req](const VertexAccessor &v_acc, const std::optional<EdgeAccessor> &e_acc) {
|
||||
if (req.property_ids) {
|
||||
if (e_acc) {
|
||||
return CollectAllPropertiesFromAccessor(*e_acc, view);
|
||||
}
|
||||
return CollectAllPropertiesFromAccessor(v_acc, view);
|
||||
}
|
||||
|
||||
if (e_acc) {
|
||||
return CollectSpecificPropertiesFromAccessor(v_acc, *req.property_ids, view);
|
||||
}
|
||||
return CollectSpecificPropertiesFromAccessor(*e_acc, *req.property_ids, view);
|
||||
};
|
||||
|
||||
auto find_edge = [](const VertexAccessor &v, msgs::EdgeId e) -> std::optional<EdgeAccessor> {
|
||||
auto in = v.InEdges(view);
|
||||
MG_ASSERT(in.HasValue());
|
||||
for (auto &edge : in.GetValue()) {
|
||||
if (edge.EdgeType() == e) {
|
||||
if (edge.Gid().AsUint() == e.gid) {
|
||||
return edge;
|
||||
}
|
||||
}
|
||||
|
||||
auto out = v.OutEdges(view, {e});
|
||||
auto out = v.OutEdges(view);
|
||||
MG_ASSERT(out.HasValue());
|
||||
for (auto &edge : out.GetValue()) {
|
||||
if (edge.EdgeType() == e) {
|
||||
if (edge.Gid().AsUint() == e.gid) {
|
||||
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);
|
||||
auto emplace_result_row =
|
||||
[dba, transform_props, collect_props, has_expr_to_evaluate, &req](
|
||||
const VertexAccessor &v_acc,
|
||||
const std::optional<EdgeAccessor> e_acc) mutable -> ShardResult<msgs::GetPropertiesResultRow> {
|
||||
auto maybe_id = v_acc.Id(view);
|
||||
if (maybe_id.HasError()) {
|
||||
return {maybe_id.GetError()};
|
||||
}
|
||||
const auto &id = maybe_id.GetValue();
|
||||
std::optional<msgs::EdgeId> e_type;
|
||||
if (e_acc) {
|
||||
e_type = msgs::EdgeId{e_acc->Gid().AsUint()};
|
||||
}
|
||||
msgs::VertexId v_id{msgs::Label{id.primary_label}, ConvertValueVector(id.primary_key)};
|
||||
auto maybe_props = collect_props(v_acc, e_acc);
|
||||
if (maybe_props.HasError()) {
|
||||
return {maybe_props.GetError()};
|
||||
}
|
||||
auto props = transform_props(std::move(maybe_props.GetValue()));
|
||||
auto result = msgs::GetPropertiesResultRow{.vertex = std::move(v_id), .edge = e_type, .props = std::move(props)};
|
||||
if (has_expr_to_evaluate) {
|
||||
std::vector<Value> e_results;
|
||||
if (e_acc) {
|
||||
e_results =
|
||||
ConvertToValueVectorFromTypedValueVector(EvaluateEdgeExpressions(dba, v_acc, *e_acc, req.expressions));
|
||||
} else {
|
||||
e_results = ConvertToValueVectorFromTypedValueVector(
|
||||
EvaluateVertexExpressions(dba, v_acc, req.expressions, expr::identifier_node_symbol));
|
||||
}
|
||||
result.evaluated_expressions = std::move(e_results);
|
||||
}
|
||||
return {std::move(result)};
|
||||
};
|
||||
|
||||
auto get_limit = [&req](const auto &elements) {
|
||||
size_t limit = elements.size();
|
||||
if (req.limit && *req.limit < elements.size()) {
|
||||
limit = *req.limit;
|
||||
}
|
||||
return limit;
|
||||
};
|
||||
|
||||
auto collect_response = [get_limit, &req](auto &elements, auto result_row_functor) {
|
||||
msgs::GetPropertiesResponse response;
|
||||
const auto limit = get_limit(elements);
|
||||
for (size_t index = 0; index != limit; ++index) {
|
||||
auto result_row = result_row_functor(elements[index]);
|
||||
if (result_row.HasError()) {
|
||||
return msgs::GetPropertiesResponse{.error = CreateErrorResponse(result_row.GetError(), req.transaction_id, "")};
|
||||
}
|
||||
response.result_row.push_back(std::move(result_row.GetValue()));
|
||||
}
|
||||
return response;
|
||||
};
|
||||
|
||||
std::vector<VertexAccessor> vertices;
|
||||
std::vector<EdgeAccessor> edges;
|
||||
|
||||
auto parse_and_filter = [dba, &vertices](auto &cont, auto projection, auto filter, auto maybe_get_edge) mutable {
|
||||
for (const auto &elem : cont) {
|
||||
const auto &[label, pk_v] = projection(elem);
|
||||
auto pk = ConvertPropertyVector(pk_v);
|
||||
auto v_acc = dba.FindVertex(pk, view);
|
||||
if (!v_acc || filter(*v_acc, maybe_get_edge(elem))) {
|
||||
continue;
|
||||
}
|
||||
vertices.push_back({*v_acc});
|
||||
}
|
||||
};
|
||||
auto identity = [](auto &elem) { return elem; };
|
||||
|
||||
auto filter_vertex = [dba, req](const auto &acc, const auto & /*edge*/) mutable {
|
||||
if (!req.filter) {
|
||||
return false;
|
||||
}
|
||||
return !FilterOnVertex(dba, acc, {*req.filter});
|
||||
};
|
||||
|
||||
auto filter_edge = [dba, &edges, &req, find_edge](const auto &acc, const auto &edge) mutable {
|
||||
auto e_acc = find_edge(acc, edge);
|
||||
if (!req.filter || !e_acc || !FilterOnEdge(dba, acc, *e_acc, {*req.filter})) {
|
||||
return false;
|
||||
}
|
||||
edges.push_back(*e_acc);
|
||||
return true;
|
||||
};
|
||||
|
||||
// Handler logic here
|
||||
if (!req.vertex_ids.empty()) {
|
||||
parse_and_filter(req.vertex_ids, identity, filter_vertex, identity);
|
||||
} else {
|
||||
parse_and_filter(
|
||||
req.vertices_and_edges, [](auto &e) { return e.first; }, filter_edge, [](auto &e) { return e.second; });
|
||||
}
|
||||
|
||||
return msgs::GetPropertiesResponse{std::move(results), msgs::GetPropertiesResponse::SUCCESS};
|
||||
if (!req.vertex_ids.empty()) {
|
||||
if (!req.order_by.empty()) {
|
||||
auto elements = OrderByVertices(dba, vertices, req.order_by);
|
||||
return collect_response(elements, [emplace_result_row](auto &element) mutable {
|
||||
return emplace_result_row(element.object_acc, std::nullopt);
|
||||
});
|
||||
}
|
||||
return collect_response(vertices,
|
||||
[emplace_result_row](auto &acc) mutable { return emplace_result_row(acc, std::nullopt); });
|
||||
}
|
||||
if (!req.order_by.empty()) {
|
||||
auto elements = OrderByEdges(dba, edges, req.order_by, vertices);
|
||||
return collect_response(elements, [emplace_result_row](auto &element) mutable {
|
||||
return emplace_result_row(element.object_acc.first, element.object_acc.second);
|
||||
});
|
||||
}
|
||||
|
||||
struct ZipView {
|
||||
ZipView(std::vector<VertexAccessor> &v, std::vector<EdgeAccessor> &e) : v(v), e(e) {}
|
||||
size_t size() const { return v.size(); }
|
||||
auto operator[](size_t index) { return std::make_pair(v[index], e[index]); }
|
||||
|
||||
private:
|
||||
std::vector<VertexAccessor> &v;
|
||||
std::vector<EdgeAccessor> &e;
|
||||
};
|
||||
|
||||
ZipView vertices_and_edges(vertices, edges);
|
||||
return collect_response(vertices_and_edges, [emplace_result_row](const auto &acc) mutable {
|
||||
return emplace_result_row(acc.first, acc.second);
|
||||
});
|
||||
}
|
||||
|
||||
// TODO(kostasrim) Handle edges
|
||||
|
||||
} // namespace memgraph::storage::v3
|
||||
|
@ -482,7 +482,7 @@ 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::vector<msgs::EdgeId> edges,
|
||||
std::optional<size_t> limit = std::nullopt,
|
||||
std::optional<uint64_t> filter_prop = std::nullopt,
|
||||
bool edge = false,
|
||||
@ -508,14 +508,25 @@ msgs::GetPropertiesResponse AttemptToGetProperties(ShardClient &client, std::vec
|
||||
req.limit = limit;
|
||||
}
|
||||
req.expressions = {std::string("5 = 5")};
|
||||
std::vector<msgs::VertexAndEdgeId> req_v;
|
||||
std::vector<msgs::VertexId> req_v;
|
||||
std::vector<msgs::EdgeId> req_e;
|
||||
for (auto &v : vertices) {
|
||||
req_v.push_back(msgs::VertexAndEdgeId{.vertex = std::move(v)});
|
||||
req_v.push_back(std::move(v));
|
||||
}
|
||||
for (auto index = 0; index != edges.size(); ++index) {
|
||||
req_v[index].edge = edges[index];
|
||||
for (auto &e : edges) {
|
||||
req_e.push_back(std::move(e));
|
||||
}
|
||||
|
||||
if (!edges.empty()) {
|
||||
MG_ASSERT(edges.size() == vertices.size());
|
||||
size_t id = 0;
|
||||
req.vertices_and_edges.reserve(req_v.size());
|
||||
for (auto &v : req_v) {
|
||||
req.vertices_and_edges.push_back({std::move(v), std::move(req_e[id++])});
|
||||
}
|
||||
} else {
|
||||
req.vertex_ids = std::move(req_v);
|
||||
}
|
||||
req.vertices_and_edges = std::move(req_v);
|
||||
|
||||
while (true) {
|
||||
auto read_res = client.SendReadRequest(req);
|
||||
@ -1285,93 +1296,86 @@ void TestGetProperties(ShardClient &client) {
|
||||
{
|
||||
// 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.error);
|
||||
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.error);
|
||||
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);
|
||||
MG_ASSERT(elem.props.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.error);
|
||||
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.error);
|
||||
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);
|
||||
MG_ASSERT(result.result_row[0].props.size() == 1);
|
||||
MG_ASSERT(result.result_row[1].props.size() == 1);
|
||||
MG_ASSERT(result.result_row[2].props.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.error);
|
||||
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.error);
|
||||
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.error);
|
||||
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);
|
||||
MG_ASSERT(result.result_row[0].vertex == v_id_3);
|
||||
MG_ASSERT(result.result_row[1].vertex == v_id_2);
|
||||
MG_ASSERT(result.result_row[2].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.error);
|
||||
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].vertex == v_id_5);
|
||||
MG_ASSERT(result.result_row[0].props.size() == 1);
|
||||
MG_ASSERT(result.result_row[0].props.front().second == prim_key_5.front());
|
||||
MG_ASSERT(result.result_row[0].props.size() == 1);
|
||||
MG_ASSERT(result.result_row[0].props.front().first == 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].vertex == v_id_4);
|
||||
MG_ASSERT(result.result_row[1].props.size() == 1);
|
||||
MG_ASSERT(result.result_row[1].props.front().second == prim_key_4.front());
|
||||
MG_ASSERT(result.result_row[1].props.size() == 1);
|
||||
MG_ASSERT(result.result_row[1].props.front().first == 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].vertex == v_id_3);
|
||||
MG_ASSERT(result.result_row[2].props.size() == 1);
|
||||
MG_ASSERT(result.result_row[2].props.front().second == prim_key_3.front());
|
||||
MG_ASSERT(result.result_row[2].props.size() == 1);
|
||||
MG_ASSERT(result.result_row[2].props.front().first == 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));
|
||||
}
|
||||
@ -1388,54 +1392,49 @@ void TestGetProperties(ShardClient &client) {
|
||||
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);
|
||||
std::vector<msgs::EdgeId> edge_ids = {{edge_gid}, {edge_gid_2}};
|
||||
// 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);
|
||||
const auto result = AttemptToGetProperties(client, {}, {v_id_2, v_id_3}, edge_ids);
|
||||
MG_ASSERT(!result.error);
|
||||
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());
|
||||
const auto result = AttemptToGetProperties(client, {edge_prop_id}, {v_id_2, v_id_3}, edge_ids);
|
||||
MG_ASSERT(!result.error);
|
||||
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());
|
||||
const auto result =
|
||||
AttemptToGetProperties(client, {edge_prop_id}, {v_id_2, v_id_3}, edge_ids, {}, {edge_prop_val}, true);
|
||||
MG_ASSERT(!result.error);
|
||||
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)));
|
||||
MG_ASSERT(result.result_row.front().edge);
|
||||
MG_ASSERT(result.result_row.front().edge.value().gid == edge_gid);
|
||||
MG_ASSERT(result.result_row.front().props.size() == 1);
|
||||
MG_ASSERT(result.result_row.front().props.front().second == 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());
|
||||
const auto result =
|
||||
AttemptToGetProperties(client, {edge_prop_id}, {v_id_2, v_id_3}, edge_ids, {}, {}, true, "e_prop");
|
||||
MG_ASSERT(!result.error);
|
||||
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].vertex == v_id_3);
|
||||
MG_ASSERT(result.result_row[0].edge);
|
||||
MG_ASSERT(result.result_row[0].edge.value().gid == edge_gid_2);
|
||||
MG_ASSERT(result.result_row[0].props.size() == 1);
|
||||
MG_ASSERT(result.result_row[0].props.front().second == 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].vertex == v_id_2);
|
||||
MG_ASSERT(result.result_row[1].edge);
|
||||
MG_ASSERT(result.result_row[1].edge.value().gid == edge_gid);
|
||||
MG_ASSERT(result.result_row[1].props.size() == 1);
|
||||
MG_ASSERT(result.result_row[1].props.front().second == 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));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user