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