1 /// Provides helper functions. 2 module memgraph.detail; 3 4 import std.conv; 5 6 import memgraph.mgclient, memgraph.enums; 7 8 /// Wrapper class around static helper functions. 9 struct Detail { 10 static string convertString(const mg_string *str) { 11 assert(str != null); 12 const auto data = mg_string_data(str); 13 const auto len = mg_string_size(str); 14 return to!string(data[0..len]); 15 } 16 17 static Type convertType(mg_value_type type) { 18 switch (type) { 19 case mg_value_type.MG_VALUE_TYPE_NULL: 20 return Type.Null; 21 case mg_value_type.MG_VALUE_TYPE_BOOL: 22 return Type.Bool; 23 case mg_value_type.MG_VALUE_TYPE_INTEGER: 24 return Type.Int; 25 case mg_value_type.MG_VALUE_TYPE_FLOAT: 26 return Type.Double; 27 case mg_value_type.MG_VALUE_TYPE_STRING: 28 return Type.String; 29 case mg_value_type.MG_VALUE_TYPE_LIST: 30 return Type.List; 31 case mg_value_type.MG_VALUE_TYPE_MAP: 32 return Type.Map; 33 case mg_value_type.MG_VALUE_TYPE_NODE: 34 return Type.Node; 35 case mg_value_type.MG_VALUE_TYPE_RELATIONSHIP: 36 return Type.Relationship; 37 case mg_value_type.MG_VALUE_TYPE_UNBOUND_RELATIONSHIP: 38 return Type.UnboundRelationship; 39 case mg_value_type.MG_VALUE_TYPE_PATH: 40 return Type.Path; 41 case mg_value_type.MG_VALUE_TYPE_DATE: 42 return Type.Date; 43 case mg_value_type.MG_VALUE_TYPE_TIME: 44 return Type.Time; 45 case mg_value_type.MG_VALUE_TYPE_LOCAL_TIME: 46 return Type.LocalTime; 47 case mg_value_type.MG_VALUE_TYPE_DATE_TIME: 48 return Type.DateTime; 49 case mg_value_type.MG_VALUE_TYPE_DATE_TIME_ZONE_ID: 50 return Type.DateTimeZoneId; 51 case mg_value_type.MG_VALUE_TYPE_LOCAL_DATE_TIME: 52 return Type.LocalDateTime; 53 case mg_value_type.MG_VALUE_TYPE_DURATION: 54 return Type.Duration; 55 case mg_value_type.MG_VALUE_TYPE_POINT_2D: 56 return Type.Point2d; 57 case mg_value_type.MG_VALUE_TYPE_POINT_3D: 58 return Type.Point3d; 59 case mg_value_type.MG_VALUE_TYPE_UNKNOWN: 60 assert(0, "unknown value type"); 61 default: 62 assert(0, "unexpected value type: " ~ to!string(type)); 63 } 64 } 65 66 static bool areValuesEqual(const mg_value *value1, const mg_value *value2) { 67 assert(value1 != null); 68 assert(value2 != null); 69 if (value1 == value2) { 70 return true; 71 } 72 if (mg_value_get_type(value1) != mg_value_get_type(value2)) { 73 return false; 74 } 75 switch (mg_value_get_type(value1)) { 76 case mg_value_type.MG_VALUE_TYPE_NULL: 77 return true; 78 case mg_value_type.MG_VALUE_TYPE_BOOL: 79 return mg_value_bool(value1) == mg_value_bool(value2); 80 case mg_value_type.MG_VALUE_TYPE_INTEGER: 81 return mg_value_integer(value1) == mg_value_integer(value2); 82 case mg_value_type.MG_VALUE_TYPE_FLOAT: 83 return mg_value_float(value1) == mg_value_float(value2); 84 case mg_value_type.MG_VALUE_TYPE_STRING: 85 return Detail.convertString(mg_value_string(value1)) == 86 Detail.convertString(mg_value_string(value2)); 87 case mg_value_type.MG_VALUE_TYPE_LIST: 88 return Detail.areListsEqual(mg_value_list(value1), 89 mg_value_list(value2)); 90 case mg_value_type.MG_VALUE_TYPE_MAP: 91 return Detail.areMapsEqual(mg_value_map(value1), mg_value_map(value2)); 92 case mg_value_type.MG_VALUE_TYPE_NODE: 93 return Detail.areNodesEqual(mg_value_node(value1), 94 mg_value_node(value2)); 95 case mg_value_type.MG_VALUE_TYPE_RELATIONSHIP: 96 return Detail.areRelationshipsEqual(mg_value_relationship(value1), 97 mg_value_relationship(value2)); 98 case mg_value_type.MG_VALUE_TYPE_UNBOUND_RELATIONSHIP: 99 return Detail.areUnboundRelationshipsEqual( 100 mg_value_unbound_relationship(value1), 101 mg_value_unbound_relationship(value2)); 102 case mg_value_type.MG_VALUE_TYPE_PATH: 103 return Detail.arePathsEqual(mg_value_path(value1), 104 mg_value_path(value2)); 105 case mg_value_type.MG_VALUE_TYPE_DATE: 106 return Detail.areDatesEqual(mg_value_date(value1), 107 mg_value_date(value2)); 108 case mg_value_type.MG_VALUE_TYPE_TIME: 109 return Detail.areTimesEqual(mg_value_time(value1), 110 mg_value_time(value2)); 111 case mg_value_type.MG_VALUE_TYPE_LOCAL_TIME: 112 return Detail.areLocalTimesEqual(mg_value_local_time(value1), 113 mg_value_local_time(value2)); 114 case mg_value_type.MG_VALUE_TYPE_DATE_TIME: 115 return Detail.areDateTimesEqual(mg_value_date_time(value1), 116 mg_value_date_time(value2)); 117 case mg_value_type.MG_VALUE_TYPE_DATE_TIME_ZONE_ID: 118 return Detail.areDateTimeZoneIdsEqual( 119 mg_value_date_time_zone_id(value1), 120 mg_value_date_time_zone_id(value2)); 121 case mg_value_type.MG_VALUE_TYPE_LOCAL_DATE_TIME: 122 return Detail.areLocalDateTimesEqual(mg_value_local_date_time(value1), 123 mg_value_local_date_time(value2)); 124 case mg_value_type.MG_VALUE_TYPE_DURATION: 125 return Detail.areDurationsEqual(mg_value_duration(value1), 126 mg_value_duration(value2)); 127 case mg_value_type.MG_VALUE_TYPE_POINT_2D: 128 return Detail.arePoint2dsEqual(mg_value_point_2d(value1), 129 mg_value_point_2d(value2)); 130 case mg_value_type.MG_VALUE_TYPE_POINT_3D: 131 return Detail.arePoint3dsEqual(mg_value_point_3d(value1), 132 mg_value_point_3d(value2)); 133 case mg_value_type.MG_VALUE_TYPE_UNKNOWN: 134 assert(0, "comparing values of unknown types!"); 135 default: assert(0, "unexpected type: " ~ to!string(mg_value_get_type(value1))); 136 } 137 } 138 139 static bool areListsEqual(const mg_list *list1, const mg_list *list2) { 140 assert(list1 != null); 141 assert(list2 != null); 142 if (list1 == list2) 143 return true; 144 if (mg_list_size(list1) != mg_list_size(list2)) 145 return false; 146 const uint len = mg_list_size(list1); 147 for (uint i = 0; i < len; ++i) { 148 if (!Detail.areValuesEqual(mg_list_at(list1, i), mg_list_at(list2, i))) 149 return false; 150 } 151 return true; 152 } 153 154 static bool areMapsEqual(const mg_map *map1, const mg_map *map2) { 155 assert(map1 != null); 156 assert(map2 != null); 157 if (map1 == map2) 158 return true; 159 if (mg_map_size(map1) != mg_map_size(map2)) 160 return false; 161 const uint len = mg_map_size(map1); 162 for (uint i = 0; i < len; ++i) { 163 const mg_string *key = mg_map_key_at(map1, i); 164 const mg_value *value1 = mg_map_value_at(map1, i); 165 const mg_value *value2 = 166 mg_map_at2(map2, mg_string_size(key), mg_string_data(key)); 167 if (value2 == null) 168 return false; 169 if (!Detail.areValuesEqual(value1, value2)) 170 return false; 171 } 172 return true; 173 } 174 175 /// Compares two nodes for equality. 176 /// Params: node1 = first node to compare 177 /// node2 = second node to compare 178 /// Return: `true` if both nodes are equal, `false` otherwise 179 static bool areNodesEqual(const mg_node *node1, const mg_node *node2) { 180 assert(node1 != null); 181 assert(node2 != null); 182 if (node1 == node2) 183 return true; 184 if (mg_node_id(node1) != mg_node_id(node2)) 185 return false; 186 if (mg_node_label_count(node1) != mg_node_label_count(node2)) 187 return false; 188 string[] labels1; 189 string[] labels2; 190 const uint label_count = mg_node_label_count(node1); 191 labels1.length = labels2.length = label_count; 192 for (uint i = 0; i < label_count; ++i) { 193 labels1[i] = Detail.convertString(mg_node_label_at(node1, i)); 194 labels2[i] = Detail.convertString(mg_node_label_at(node2, i)); 195 } 196 if (labels1 != labels2) 197 return false; 198 return Detail.areMapsEqual(mg_node_properties(node1), 199 mg_node_properties(node2)); 200 } // areNodesEqual() 201 202 static bool areRelationshipsEqual(const mg_relationship *rel1, 203 const mg_relationship *rel2) { 204 assert(rel1 != null); 205 assert(rel2 != null); 206 if (rel1 == rel2) 207 return true; 208 if (mg_relationship_id(rel1) != mg_relationship_id(rel2)) 209 return false; 210 if (mg_relationship_start_id(rel1) != mg_relationship_start_id(rel2)) 211 return false; 212 if (mg_relationship_end_id(rel1) != mg_relationship_end_id(rel2)) 213 return false; 214 if (Detail.convertString(mg_relationship_type(rel1)) != 215 Detail.convertString(mg_relationship_type(rel2))) 216 return false; 217 return Detail.areMapsEqual(mg_relationship_properties(rel1), 218 mg_relationship_properties(rel2)); 219 } 220 221 static bool areUnboundRelationshipsEqual(const mg_unbound_relationship *rel1, 222 const mg_unbound_relationship *rel2) { 223 assert(rel1 != null); 224 assert(rel2 != null); 225 if (rel1 == rel2) 226 return true; 227 if (mg_unbound_relationship_id(rel1) != mg_unbound_relationship_id(rel2)) 228 return false; 229 if (Detail.convertString(mg_unbound_relationship_type(rel1)) != 230 Detail.convertString(mg_unbound_relationship_type(rel2))) 231 return false; 232 return Detail.areMapsEqual(mg_unbound_relationship_properties(rel1), 233 mg_unbound_relationship_properties(rel2)); 234 } 235 236 static bool arePathsEqual(const mg_path *path1, const mg_path *path2) { 237 assert(path1 != null); 238 assert(path2 != null); 239 if (path1 == path2) 240 return true; 241 if (mg_path_length(path1) != mg_path_length(path2)) 242 return false; 243 const uint len = mg_path_length(path1); 244 for (uint i = 0; i < len; ++i) { 245 if (!Detail.areNodesEqual(mg_path_node_at(path1, i), 246 mg_path_node_at(path2, i))) { 247 return false; 248 } 249 if (!Detail.areUnboundRelationshipsEqual( 250 mg_path_relationship_at(path1, i), 251 mg_path_relationship_at(path2, i))) { 252 return false; 253 } 254 if (mg_path_relationship_reversed_at(path1, i) != 255 mg_path_relationship_reversed_at(path2, i)) { 256 return false; 257 } 258 } 259 return Detail.areNodesEqual(mg_path_node_at(path1, len), 260 mg_path_node_at(path2, len)); 261 } 262 263 static bool areDatesEqual(const mg_date *date1, const mg_date *date2) { 264 assert(date1 != null); 265 assert(date2 != null); 266 return mg_date_days(date1) == mg_date_days(date2); 267 } 268 269 static bool areTimesEqual(const mg_time *time1, const mg_time *time2) { 270 assert(time1 != null); 271 assert(time2 != null); 272 return mg_time_nanoseconds(time1) == mg_time_nanoseconds(time2) && 273 mg_time_tz_offset_seconds(time1) == mg_time_tz_offset_seconds(time2); 274 } 275 276 static bool areLocalTimesEqual(const mg_local_time *local_time1, 277 const mg_local_time *local_time2) { 278 assert(local_time1 != null); 279 assert(local_time2 != null); 280 return mg_local_time_nanoseconds(local_time1) == 281 mg_local_time_nanoseconds(local_time2); 282 } 283 284 static bool areDateTimesEqual(const mg_date_time *date_time1, 285 const mg_date_time *date_time2) { 286 assert(date_time1 != null); 287 assert(date_time2 != null); 288 return mg_date_time_seconds(date_time1) == mg_date_time_seconds(date_time2) && 289 mg_date_time_nanoseconds(date_time1) == 290 mg_date_time_nanoseconds(date_time2) && 291 mg_date_time_tz_offset_minutes(date_time1) == 292 mg_date_time_tz_offset_minutes(date_time2); 293 } 294 295 static bool areDateTimeZoneIdsEqual( 296 const mg_date_time_zone_id *date_time_zone_id1, 297 const mg_date_time_zone_id *date_time_zone_id2) { 298 assert(date_time_zone_id1 != null); 299 assert(date_time_zone_id2 != null); 300 return mg_date_time_zone_id_seconds(date_time_zone_id1) == 301 mg_date_time_zone_id_seconds(date_time_zone_id2) && 302 mg_date_time_zone_id_nanoseconds(date_time_zone_id1) == 303 mg_date_time_zone_id_nanoseconds(date_time_zone_id2) && 304 mg_date_time_zone_id_tz_id(date_time_zone_id1) == 305 mg_date_time_zone_id_tz_id(date_time_zone_id2); 306 } 307 308 static bool areLocalDateTimesEqual(const mg_local_date_time *local_date_time1, 309 const mg_local_date_time *local_date_time2) { 310 assert(local_date_time1 != null); 311 assert(local_date_time2 != null); 312 return mg_local_date_time_seconds(local_date_time1) == 313 mg_local_date_time_seconds(local_date_time2) && 314 mg_local_date_time_nanoseconds(local_date_time1) == 315 mg_local_date_time_nanoseconds(local_date_time2); 316 } 317 318 static bool areDurationsEqual(const mg_duration *duration1, 319 const mg_duration *duration2) { 320 assert(duration1 != null); 321 assert(duration2 != null); 322 return mg_duration_months(duration1) == mg_duration_months(duration2) && 323 mg_duration_days(duration1) == mg_duration_days(duration2) && 324 mg_duration_seconds(duration1) == mg_duration_seconds(duration2) && 325 mg_duration_nanoseconds(duration1) == 326 mg_duration_nanoseconds(duration2); 327 } 328 329 static bool arePoint2dsEqual(const mg_point_2d *point_2d1, 330 const mg_point_2d *point_2d2) { 331 assert(point_2d1 != null); 332 assert(point_2d2 != null); 333 return mg_point_2d_srid(point_2d1) == mg_point_2d_srid(point_2d2) && 334 mg_point_2d_x(point_2d1) == mg_point_2d_x(point_2d2) && 335 mg_point_2d_y(point_2d1) == mg_point_2d_y(point_2d2); 336 } 337 338 static bool arePoint3dsEqual(const mg_point_3d *point_3d1, 339 const mg_point_3d *point_3d2) { 340 assert(point_3d1 != null); 341 assert(point_3d2 != null); 342 return mg_point_3d_srid(point_3d1) == mg_point_3d_srid(point_3d2) && 343 mg_point_3d_x(point_3d1) == mg_point_3d_x(point_3d2) && 344 mg_point_3d_y(point_3d1) == mg_point_3d_y(point_3d2) && 345 mg_point_3d_z(point_3d1) == mg_point_3d_z(point_3d2); 346 } 347 }