Add ToString on C++ API mgp types(#1140)

This commit is contained in:
Matija Pintarić 2023-08-29 17:30:23 +02:00 committed by GitHub
parent a6ec81b179
commit d516e40841
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 252 additions and 0 deletions

View File

@ -554,6 +554,9 @@ class List {
/// @exception std::runtime_error List contains value of unknown type.
bool operator!=(const List &other) const;
/// @brief returns the string representation
const std::string ToString() const;
private:
mgp_list *ptr_;
};
@ -669,6 +672,9 @@ class Map {
/// @exception std::runtime_error Map contains value of unknown type.
bool operator!=(const Map &other) const;
/// @brief returns the string representation
const std::string ToString() const;
private:
mgp_map *ptr_;
};
@ -740,6 +746,9 @@ class Node {
/// @exception std::runtime_error Node properties contain value(s) of unknown type.
bool operator!=(const Node &other) const;
/// @brief returns the string representation
const std::string ToString() const;
private:
mgp_vertex *ptr_;
};
@ -798,6 +807,9 @@ class Relationship {
/// @exception std::runtime_error Relationship properties contain value(s) of unknown type.
bool operator!=(const Relationship &other) const;
/// @brief returns the string representation
const std::string ToString() const;
private:
mgp_edge *ptr_;
};
@ -846,6 +858,9 @@ class Path {
/// @exception std::runtime_error Path contains element(s) with unknown value.
bool operator!=(const Path &other) const;
/// @brief returns the string representation
const std::string ToString() const;
private:
mgp_path *ptr_;
};
@ -903,6 +918,9 @@ class Date {
bool operator<(const Date &other) const;
/// @brief returns the string representation
const std::string ToString() const;
private:
mgp_date *ptr_;
};
@ -962,6 +980,9 @@ class LocalTime {
bool operator<(const LocalTime &other) const;
/// @brief returns the string representation
const std::string ToString() const;
private:
mgp_local_time *ptr_;
};
@ -1027,6 +1048,9 @@ class LocalDateTime {
bool operator<(const LocalDateTime &other) const;
/// @brief returns the string representation
const std::string ToString() const;
private:
mgp_local_date_time *ptr_;
};
@ -1078,6 +1102,9 @@ class Duration {
bool operator<(const Duration &other) const;
/// @brief returns the string representation
const std::string ToString() const;
private:
mgp_duration *ptr_;
};
@ -1288,6 +1315,9 @@ class Value {
friend std::ostream &operator<<(std::ostream &os, const mgp::Value &value);
/// @brief returns the string representation
const std::string ToString() const;
private:
mgp_value *ptr_;
};
@ -2400,6 +2430,22 @@ inline bool List::operator==(const List &other) const { return util::ListsEqual(
inline bool List::operator!=(const List &other) const { return !(*this == other); }
inline const std::string List::ToString() const {
const size_t size = Size();
if (size == 0) {
return "[]";
}
std::string return_str{"["};
size_t i = 0;
const mgp::List &list = (*this);
while (i < size - 1) {
return_str.append(list[i].ToString() + ", ");
i++;
}
return_str.append(list[i].ToString() + "]");
return return_str;
}
// MapItem:
inline bool MapItem::operator==(MapItem &other) const { return key == other.key && value == other.value; }
@ -2569,6 +2615,24 @@ inline bool Map::operator==(const Map &other) const { return util::MapsEqual(ptr
inline bool Map::operator!=(const Map &other) const { return !(*this == other); }
inline const std::string Map::ToString() const {
const size_t map_size = Size();
if (map_size == 0) {
return "{}";
}
std::string return_string{"{"};
size_t i = 0;
for (const auto &[key, value] : *this) {
if (i == map_size - 1) {
return_string.append(std::string(key) + ": " + value.ToString() + "}");
break;
}
return_string.append(std::string(key) + ": " + value.ToString() + ", ");
++i;
}
return return_string;
}
/* #endregion */
/* #region Graph elements (Node, Relationship & Path) */
@ -2674,6 +2738,35 @@ inline bool Node::operator==(const Node &other) const { return util::NodesEqual(
inline bool Node::operator!=(const Node &other) const { return !(*this == other); }
// this functions is used both in relationship and node ToString
inline std::string PropertiesToString(const std::map<std::string, Value> &property_map) {
std::string properties{""};
const auto map_size = property_map.size();
size_t i = 0;
for (const auto &[key, value] : property_map) {
if (i == map_size - 1) {
properties.append(std::string(key) + ": " + value.ToString());
break;
}
properties.append(std::string(key) + ": " + value.ToString() + ", ");
++i;
}
return properties;
}
inline const std::string Node::ToString() const {
std::string labels{", "};
for (auto label : Labels()) {
labels.append(":" + std::string(label));
}
if (labels == ", ") {
labels = ""; // dont use labels if they dont exist
}
std::map<std::string, Value> properties_map{Properties()};
std::string properties{PropertiesToString(properties_map)};
return "(id: " + std::to_string(Id().AsInt()) + labels + ", properties: {" + properties + "})";
}
// Relationship:
inline Relationship::Relationship(mgp_edge *ptr) : ptr_(mgp::MemHandlerCallback(edge_copy, ptr)) {}
@ -2748,6 +2841,18 @@ inline bool Relationship::operator==(const Relationship &other) const {
inline bool Relationship::operator!=(const Relationship &other) const { return !(*this == other); }
inline const std::string Relationship::ToString() const {
const auto from = From();
const auto to = To();
const std::string type{Type()};
std::map<std::string, Value> properties_map{Properties()};
std::string properties{PropertiesToString(properties_map)};
const std::string relationship{"[type: " + type + ", id: " + std::to_string(Id().AsInt()) + ", properties: {" +
properties + "}]"};
return from.ToString() + "-" + relationship + "->" + to.ToString();
}
// Path:
inline Path::Path(mgp_path *ptr) : ptr_(mgp::MemHandlerCallback(path_copy, ptr)) {}
@ -2810,6 +2915,26 @@ inline bool Path::operator==(const Path &other) const { return util::PathsEqual(
inline bool Path::operator!=(const Path &other) const { return !(*this == other); }
inline const std::string Path::ToString() const {
const auto length = Length();
size_t i = 0;
std::string return_string{""};
for (i = 0; i < length; i++) {
const auto node = GetNodeAt(i);
return_string.append(node.ToString() + "-");
const Relationship rel = GetRelationshipAt(i);
std::map<std::string, Value> properties_map{rel.Properties()};
std::string properties = PropertiesToString(properties_map);
return_string.append("[type: " + std::string(rel.Type()) + ", id: " + std::to_string(rel.Id().AsInt()) +
", properties: {" + properties + "}]->");
}
const auto node = GetNodeAt(i);
return_string.append(node.ToString());
return return_string;
}
/* #endregion */
/* #region Temporal types (Date, LocalTime, LocalDateTime, Duration) */
@ -2907,6 +3032,10 @@ inline bool Date::operator<(const Date &other) const {
return is_less;
}
inline const std::string Date::ToString() const {
return std::to_string(Year()) + "-" + std::to_string(Month()) + "-" + std::to_string(Day());
}
// LocalTime:
inline LocalTime::LocalTime(mgp_local_time *ptr) : ptr_(mgp::MemHandlerCallback(local_time_copy, ptr)) {}
@ -3006,6 +3135,11 @@ inline bool LocalTime::operator<(const LocalTime &other) const {
return is_less;
}
inline const std::string LocalTime::ToString() const {
return std::to_string(Hour()) + ":" + std::to_string(Minute()) + ":" + std::to_string(Second()) + "," +
std::to_string(Millisecond()) + std::to_string(Microsecond());
}
// LocalDateTime:
inline LocalDateTime::LocalDateTime(mgp_local_date_time *ptr)
@ -3120,6 +3254,12 @@ inline bool LocalDateTime::operator<(const LocalDateTime &other) const {
return is_less;
}
inline const std::string LocalDateTime::ToString() const {
return std::to_string(Year()) + "-" + std::to_string(Month()) + "-" + std::to_string(Day()) + "T" +
std::to_string(Hour()) + ":" + std::to_string(Minute()) + ":" + std::to_string(Second()) + "," +
std::to_string(Millisecond()) + std::to_string(Microsecond());
}
// Duration:
inline Duration::Duration(mgp_duration *ptr) : ptr_(mgp::MemHandlerCallback(duration_copy, ptr)) {}
@ -3209,6 +3349,8 @@ inline bool Duration::operator<(const Duration &other) const {
return is_less;
}
inline const std::string Duration::ToString() const { return std::to_string(Microseconds()) + "ms"; }
/* #endregion */
/* #endregion */
@ -3673,6 +3815,42 @@ inline std::ostream &operator<<(std::ostream &os, const mgp::Type &type) {
}
}
inline const std::string Value::ToString() const {
const mgp::Type &type = Type();
switch (type) {
case Type::Null:
return "";
case Type::Bool:
return ValueBool() ? "true" : "false";
case Type::Int:
return std::to_string(ValueInt());
case Type::Double:
return std::to_string(ValueDouble());
case Type::String:
return std::string(ValueString());
case Type::Node:
return ValueNode().ToString();
case Type::Relationship:
return ValueRelationship().ToString();
case Type::Date:
return ValueDate().ToString();
case Type::LocalTime:
return ValueLocalTime().ToString();
case Type::LocalDateTime:
return ValueLocalDateTime().ToString();
case Type::Duration:
return ValueDuration().ToString();
case Type::List:
return ValueList().ToString();
case Type::Map:
return ValueMap().ToString();
case Type::Path:
return ValuePath().ToString();
default:
throw ValueException("Undefined behaviour");
}
}
/* #endregion */
/* #region Record */

View File

@ -615,3 +615,77 @@ TYPED_TEST(CppApiTestFixture, TestValuePrint) {
std::string date_test = oss_date.str();
ASSERT_EQ("2020-12-12", date_test);
}
TYPED_TEST(CppApiTestFixture, TestValueToString) {
/*graph and node shared by multiple types*/
mgp_graph raw_graph = this->CreateGraph(memgraph::storage::View::NEW);
auto graph = mgp::Graph(&raw_graph);
/*null*/
ASSERT_EQ(mgp::Value().ToString(), "");
/*bool*/
ASSERT_EQ(mgp::Value(false).ToString(), "false");
/*int*/
const int64_t int1 = 60;
ASSERT_EQ(mgp::Value(int1).ToString(), "60");
/*double*/
const double double1 = 2.567891;
ASSERT_EQ(mgp::Value(double1).ToString(), "2.567891");
/*string*/
const std::string str = "string";
ASSERT_EQ(mgp::Value(str).ToString(), "string");
/*list*/
mgp::List list;
auto node_list = graph.CreateNode();
node_list.AddLabel("Label_list");
list.AppendExtend(mgp::Value("inside"));
list.AppendExtend(mgp::Value("2"));
list.AppendExtend(mgp::Value(node_list));
ASSERT_EQ(mgp::Value(list).ToString(), "[inside, 2, (id: 0, :Label_list, properties: {})]");
/*map*/
mgp::Map map;
auto node_map = graph.CreateNode();
node_map.AddLabel("Label_map");
map.Insert("key", mgp::Value(int1));
map.Insert("node", mgp::Value(node_map));
ASSERT_EQ(mgp::Value(map).ToString(), "{key: 60, node: (id: 1, :Label_map, properties: {})}");
/*date*/
mgp::Date date_1{"2020-12-12"};
ASSERT_EQ(mgp::Value(date_1).ToString(), "2020-12-12");
/*local time*/
mgp::LocalTime local_time{"09:15:00.360"};
ASSERT_EQ(mgp::Value(local_time).ToString(), "9:15:0,3600");
/*local date time*/
mgp::LocalDateTime local_date_time{"2021-10-05T14:15:00"};
ASSERT_EQ(mgp::Value(local_date_time).ToString(), "2021-10-5T14:15:0,00");
/*duration*/
mgp::Duration duration{"P14DT17H2M45S"};
ASSERT_EQ(mgp::Value(duration).ToString(), "1270965000000ms");
/*node and relationship*/
auto node1 = graph.CreateNode();
node1.AddLabel("Label1");
node1.AddLabel("Label2");
auto node2 = graph.CreateNode();
node2.SetProperty("key", mgp::Value("node_property"));
node2.SetProperty("key2", mgp::Value("node_property2"));
auto rel = graph.CreateRelationship(node1, node2, "Loves");
rel.SetProperty("key", mgp::Value("property"));
ASSERT_EQ(mgp::Value(rel).ToString(),
"(id: 2, :Label1:Label2, properties: {})-[type: Loves, id: 0, properties: {key: property}]->(id: 3, "
"properties: {key: node_property, key2: node_property2})");
/*path*/
mgp::Path path = mgp::Path(node1);
path.Expand(rel);
auto node3 = graph.CreateNode();
auto rel2 = graph.CreateRelationship(node2, node3, "Loves2");
path.Expand(rel2);
ASSERT_EQ(
mgp::Value(path).ToString(),
"(id: 2, :Label1:Label2, properties: {})-[type: Loves, id: 0, properties: {key: property}]->(id: 3, properties: "
"{key: node_property, key2: node_property2})-[type: Loves2, id: 1, properties: {}]->(id: 4, properties: {})");
}