add serialization for graph
This commit is contained in:
parent
60c1412416
commit
78c459de1a
src
communication/bolt/v1
glue
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
};
|
||||
};
|
||||
/**
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user