add serialization for graph

This commit is contained in:
antoniofilipovic 2022-07-25 13:38:43 +02:00
parent 60c1412416
commit 78c459de1a
5 changed files with 119 additions and 2 deletions

View File

@ -181,6 +181,17 @@ class BaseEncoder {
for (auto &i : path.indices) WriteInt(i);
}
void WriteGraph(const Graph &graph) {
WriteRAW(utils::UnderlyingCast(Marker::TinyStruct) + 3);
WriteRAW(utils::UnderlyingCast(Signature::Path)); // todo fico, fix
WriteTypeSize(graph.vertices.size(), MarkerList);
for (auto &v : graph.vertices) WriteVertex(v);
WriteTypeSize(graph.edges.size(), MarkerList);
for (auto &e : graph.edges) WriteEdge(e);
WriteTypeSize(graph.indices.size(), MarkerList);
for (auto &i : graph.indices) WriteInt(i);
}
void WriteDate(const utils::Date &date) {
WriteRAW(utils::UnderlyingCast(Marker::TinyStruct1));
WriteRAW(utils::UnderlyingCast(Signature::Date));
@ -259,6 +270,9 @@ class BaseEncoder {
case Value::Type::Duration:
WriteDuration(value.ValueDuration());
break;
case Value::Type::Graph:
WriteGraph(value.ValueGraph());
break;
}
}

View File

@ -54,6 +54,7 @@ DEF_GETTER_BY_REF(Date, utils::Date, date_v)
DEF_GETTER_BY_REF(LocalTime, utils::LocalTime, local_time_v)
DEF_GETTER_BY_REF(LocalDateTime, utils::LocalDateTime, local_date_time_v)
DEF_GETTER_BY_REF(Duration, utils::Duration, duration_v)
DEF_GETTER_BY_REF(Graph, Graph, graph_v)
#undef DEF_GETTER_BY_REF
@ -103,6 +104,8 @@ Value::Value(const Value &other) : type_(other.type_) {
case Type::Duration:
new (&duration_v) utils::Duration(other.duration_v);
return;
case Type::Graph:
throw ValueException();
}
}
@ -157,6 +160,9 @@ Value &Value::operator=(const Value &other) {
case Type::Duration:
new (&duration_v) utils::Duration(other.duration_v);
return *this;
case Type::Graph:
new (&graph_v) Graph(other.graph_v);
return *this;
}
}
return *this;
@ -208,6 +214,9 @@ Value::Value(Value &&other) noexcept : type_(other.type_) {
case Type::Duration:
new (&duration_v) utils::Duration(other.duration_v);
break;
case Type::Graph:
new (&graph_v) Graph(std::move(other.graph_v));
break;
}
// reset the type of other
@ -266,6 +275,9 @@ Value &Value::operator=(Value &&other) noexcept {
case Type::Duration:
new (&duration_v) utils::Duration(other.duration_v);
break;
case Type::Graph:
new (&graph_v) Graph(std::move(other.graph_v));
break;
}
// reset the type of other
@ -324,6 +336,9 @@ Value::~Value() {
case Type::Duration:
duration_v.~Duration();
return;
case Type::Graph:
graph_v.~Graph();
return;
}
}
@ -424,6 +439,8 @@ std::ostream &operator<<(std::ostream &os, const Value &value) {
return os << value.ValueLocalDateTime();
case Value::Type::Duration:
return os << value.ValueDuration();
case Value::Type::Graph:
throw ValueException("Not supported for Graph");
}
}
@ -459,6 +476,8 @@ std::ostream &operator<<(std::ostream &os, const Value::Type type) {
return os << "local_date_time";
case Value::Type::Duration:
return os << "duration";
case Value::Type::Graph:
throw ValueException("error");
}
}
} // namespace memgraph::communication::bolt

View File

@ -125,6 +125,50 @@ struct Path {
std::vector<int64_t> indices;
};
/**
* Structure used when reading a Graph with the decoder.
* The decoder writes data into this structure.
*/
struct Graph {
Graph() {}
Graph(const std::vector<Vertex> &vertices, const std::vector<Edge> &edges) {
// Helper function. Looks for the given element in the collection. If found,
// puts its index into `indices`. Otherwise emplaces the given element
// into the collection and puts that index into `indices`. A multiplier is
// added to switch between positive and negative indices (that define edge
// direction).
auto add_element = [this](auto &collection, const auto &element, int multiplier, int offset) {
auto found =
std::find_if(collection.begin(), collection.end(), [&](const auto &e) { return e.id == element.id; });
indices.emplace_back(multiplier * (std::distance(collection.begin(), found) + offset));
if (found == collection.end()) collection.push_back(element);
};
this->vertices.reserve(vertices.size());
this->edges.reserve(edges.size());
this->vertices.emplace_back(vertices[0]);
for (uint i = 0; i < edges.size(); i++) {
const auto &e = edges[i];
const auto &v = vertices[i + 1];
UnboundedEdge unbounded_edge{e.id, e.type, e.properties};
add_element(this->edges, unbounded_edge, e.to == v.id ? 1 : -1, 1);
add_element(this->vertices, v, 1, 0);
}
}
/** Unique vertices in the path. */
std::vector<Vertex> vertices;
/** Unique edges in the path. */
std::vector<UnboundedEdge> edges;
/**
* Indices that map path positions to vertices/edges.
* Positive indices for left-to-right directionality and negative for
* right-to-left.
*/
std::vector<int64_t> indices;
};
/** Value represents supported values in the Bolt protocol. */
class Value {
public:
@ -147,7 +191,8 @@ class Value {
Date,
LocalTime,
LocalDateTime,
Duration
Duration,
Graph
};
// constructors for primitive types
@ -167,6 +212,8 @@ class Value {
Value(const Edge &value) : type_(Type::Edge) { new (&edge_v) Edge(value); }
Value(const UnboundedEdge &value) : type_(Type::UnboundedEdge) { new (&unbounded_edge_v) UnboundedEdge(value); }
Value(const Path &value) : type_(Type::Path) { new (&path_v) Path(value); }
Value(const Graph &value) : type_(Type::Graph) { new (&graph_v) Graph(value); }
Value(const utils::Date &date) : type_(Type::Date) { new (&date_v) utils::Date(date); }
Value(const utils::LocalTime &time) : type_(Type::LocalTime) { new (&local_time_v) utils::LocalTime(time); }
Value(const utils::LocalDateTime &date_time) : type_(Type::LocalDateTime) {
@ -185,6 +232,7 @@ class Value {
new (&unbounded_edge_v) UnboundedEdge(std::move(value));
}
Value(Path &&value) noexcept : type_(Type::Path) { new (&path_v) Path(std::move(value)); }
Value(Graph &&value) noexcept : type_(Type::Graph) { new (&graph_v) Graph(std::move(value)); }
Value &operator=(const Value &other);
Value &operator=(Value &&other) noexcept;
@ -220,6 +268,7 @@ class Value {
DECL_GETTER_BY_REFERENCE(LocalTime, utils::LocalTime)
DECL_GETTER_BY_REFERENCE(LocalDateTime, utils::LocalDateTime)
DECL_GETTER_BY_REFERENCE(Duration, utils::Duration)
DECL_GETTER_BY_REFERENCE(Graph, Graph)
#undef DECL_GETTER_BY_REFERNCE
#define TYPE_CHECKER(type) \
@ -239,6 +288,7 @@ class Value {
TYPE_CHECKER(LocalTime)
TYPE_CHECKER(LocalDateTime)
TYPE_CHECKER(Duration)
TYPE_CHECKER(Graph)
#undef TYPE_CHECKER
friend std::ostream &operator<<(std::ostream &os, const Value &value);
@ -262,6 +312,7 @@ class Value {
utils::LocalTime local_time_v;
utils::LocalDateTime local_date_time_v;
utils::Duration duration_v;
Graph graph_v;
};
};
/**

View File

@ -60,6 +60,8 @@ query::TypedValue ToTypedValue(const Value &value) {
return query::TypedValue(value.ValueLocalDateTime());
case Value::Type::Duration:
return query::TypedValue(value.ValueDuration());
case Value::Type::Graph:
throw communication::bolt::ValueException("Unsupported conversion from Value to TypedValue");
}
}
@ -128,7 +130,9 @@ storage::Result<Value> ToBoltValue(const query::TypedValue &value, const storage
case query::TypedValue::Type::Duration:
return Value(value.ValueDuration());
case query::TypedValue::Type::Graph:
throw communication::bolt::ValueException("Unsupported conversion from TypedValue to Value for Graph");
auto maybe_graph = ToBoltGraph(value.ValueGraph(), db, view);
if (maybe_graph.HasError()) return maybe_graph.GetError();
return Value(std::move(*maybe_graph));
}
}
@ -185,6 +189,25 @@ storage::Result<communication::bolt::Path> ToBoltPath(const query::Path &path, c
return communication::bolt::Path(vertices, edges);
}
storage::Result<communication::bolt::Graph> ToBoltGraph(const query::Graph &graph, const storage::Storage &db,
storage::View view) {
std::vector<communication::bolt::Vertex> vertices;
vertices.reserve(graph.vertices().size());
for (const auto &v : graph.vertices()) {
auto maybe_vertex = ToBoltVertex(v, db, view);
if (maybe_vertex.HasError()) return maybe_vertex.GetError();
vertices.emplace_back(std::move(*maybe_vertex));
}
std::vector<communication::bolt::Edge> edges;
edges.reserve(graph.edges().size());
for (const auto &e : graph.edges()) {
auto maybe_edge = ToBoltEdge(e, db, view);
if (maybe_edge.HasError()) return maybe_edge.GetError();
edges.emplace_back(std::move(*maybe_edge));
}
return communication::bolt::Graph(vertices, edges);
}
storage::PropertyValue ToPropertyValue(const Value &value) {
switch (value.type()) {
case Value::Type::Null:
@ -225,6 +248,8 @@ storage::PropertyValue ToPropertyValue(const Value &value) {
case Value::Type::Duration:
return storage::PropertyValue(
storage::TemporalData(storage::TemporalType::Duration, value.ValueDuration().microseconds));
case Value::Type::Graph:
throw communication::bolt::ValueException("Unsupported conversion from Value to PropertyValue");
}
}

View File

@ -51,6 +51,14 @@ storage::Result<communication::bolt::Edge> ToBoltEdge(const storage::EdgeAccesso
storage::Result<communication::bolt::Path> ToBoltPath(const query::Path &path, const storage::Storage &db,
storage::View view);
/// @param query::Graph for converting to communication::bolt::Graph.
/// @param storage::Storage for ToBoltVertex and ToBoltEdge.
/// @param storage::View for ToBoltVertex and ToBoltEdge.
///
/// @throw std::bad_alloc
storage::Result<communication::bolt::Graph> ToBoltGraph(const query::Graph &graph, const storage::Storage &db,
storage::View view);
/// @param query::TypedValue for converting to communication::bolt::Value.
/// @param storage::Storage for ToBoltVertex and ToBoltEdge.
/// @param storage::View for ToBoltVertex and ToBoltEdge.