1 /// Provides helper functions. 2 module memgraph.detail; 3 4 import memgraph.mgclient, memgraph.enums; 5 6 /// Wrapper class around static helper functions. 7 struct Detail { 8 /// Converts a `mg_string` to a D string. 9 @nogc static string convertString(const mg_string *str) { 10 assert(str != null); 11 const auto data = mg_string_data(str); 12 const auto len = mg_string_size(str); 13 return cast(string)data[0..len]; 14 } 15 16 unittest { 17 const p = mg_string_make("Some test string"); 18 assert(p != null); 19 const s = Detail.convertString(p); 20 assert(s == "Some test string"); 21 } 22 23 /// Converts a `mg_value_type` enum to a `Type` enum. 24 @nogc static Type convertType(mg_value_type type) { 25 final switch (type) { 26 case mg_value_type.MG_VALUE_TYPE_NULL: 27 return Type.Null; 28 case mg_value_type.MG_VALUE_TYPE_BOOL: 29 return Type.Bool; 30 case mg_value_type.MG_VALUE_TYPE_INTEGER: 31 return Type.Int; 32 case mg_value_type.MG_VALUE_TYPE_FLOAT: 33 return Type.Double; 34 case mg_value_type.MG_VALUE_TYPE_STRING: 35 return Type.String; 36 case mg_value_type.MG_VALUE_TYPE_LIST: 37 return Type.List; 38 case mg_value_type.MG_VALUE_TYPE_MAP: 39 return Type.Map; 40 case mg_value_type.MG_VALUE_TYPE_NODE: 41 return Type.Node; 42 case mg_value_type.MG_VALUE_TYPE_RELATIONSHIP: 43 return Type.Relationship; 44 case mg_value_type.MG_VALUE_TYPE_UNBOUND_RELATIONSHIP: 45 return Type.UnboundRelationship; 46 case mg_value_type.MG_VALUE_TYPE_PATH: 47 return Type.Path; 48 case mg_value_type.MG_VALUE_TYPE_DATE: 49 return Type.Date; 50 case mg_value_type.MG_VALUE_TYPE_TIME: 51 assert(0); 52 case mg_value_type.MG_VALUE_TYPE_LOCAL_TIME: 53 return Type.LocalTime; 54 case mg_value_type.MG_VALUE_TYPE_DATE_TIME: 55 assert(0); 56 case mg_value_type.MG_VALUE_TYPE_DATE_TIME_ZONE_ID: 57 assert(0); 58 case mg_value_type.MG_VALUE_TYPE_LOCAL_DATE_TIME: 59 return Type.LocalDateTime; 60 case mg_value_type.MG_VALUE_TYPE_DURATION: 61 return Type.Duration; 62 case mg_value_type.MG_VALUE_TYPE_POINT_2D: 63 return Type.Point2d; 64 case mg_value_type.MG_VALUE_TYPE_POINT_3D: 65 return Type.Point3d; 66 case mg_value_type.MG_VALUE_TYPE_UNKNOWN: 67 assert(0, "unknown value type"); 68 } 69 } 70 71 unittest { 72 assert(Detail.convertType(mg_value_type.MG_VALUE_TYPE_NULL) == Type.Null); 73 assert(Detail.convertType(mg_value_type.MG_VALUE_TYPE_BOOL) == Type.Bool); 74 assert(Detail.convertType(mg_value_type.MG_VALUE_TYPE_INTEGER) == Type.Int); 75 assert(Detail.convertType(mg_value_type.MG_VALUE_TYPE_FLOAT) == Type.Double); 76 assert(Detail.convertType(mg_value_type.MG_VALUE_TYPE_STRING) == Type.String); 77 assert(Detail.convertType(mg_value_type.MG_VALUE_TYPE_LIST) == Type.List); 78 assert(Detail.convertType(mg_value_type.MG_VALUE_TYPE_MAP) == Type.Map); 79 assert(Detail.convertType(mg_value_type.MG_VALUE_TYPE_NODE) == Type.Node); 80 assert(Detail.convertType(mg_value_type.MG_VALUE_TYPE_RELATIONSHIP) == Type.Relationship); 81 assert(Detail.convertType(mg_value_type.MG_VALUE_TYPE_UNBOUND_RELATIONSHIP) == Type.UnboundRelationship); 82 assert(Detail.convertType(mg_value_type.MG_VALUE_TYPE_PATH) == Type.Path); 83 assert(Detail.convertType(mg_value_type.MG_VALUE_TYPE_DATE) == Type.Date); 84 assert(Detail.convertType(mg_value_type.MG_VALUE_TYPE_LOCAL_TIME) == Type.LocalTime); 85 assert(Detail.convertType(mg_value_type.MG_VALUE_TYPE_LOCAL_DATE_TIME) == Type.LocalDateTime); 86 assert(Detail.convertType(mg_value_type.MG_VALUE_TYPE_DURATION) == Type.Duration); 87 assert(Detail.convertType(mg_value_type.MG_VALUE_TYPE_POINT_2D) == Type.Point2d); 88 assert(Detail.convertType(mg_value_type.MG_VALUE_TYPE_POINT_3D) == Type.Point3d); 89 90 import std.exception, core.exception; 91 92 // The following types are currently not supported, pending addition 93 // of the appropriate temporal functions to the memgraph backend. 94 assertThrown!AssertError(Detail.convertType(mg_value_type.MG_VALUE_TYPE_TIME)); 95 assertThrown!AssertError(Detail.convertType(mg_value_type.MG_VALUE_TYPE_DATE_TIME)); 96 assertThrown!AssertError(Detail.convertType(mg_value_type.MG_VALUE_TYPE_DATE_TIME_ZONE_ID)); 97 98 // Check for "unknown" type. 99 assertThrown!AssertError(Detail.convertType(mg_value_type.MG_VALUE_TYPE_UNKNOWN)); 100 } 101 102 /// Compares two `mg_value`s. 103 @nogc static bool areValuesEqual(const mg_value *value1, const mg_value *value2) { 104 assert(value1 != null); 105 assert(value2 != null); 106 if (value1 == value2) { 107 return true; 108 } 109 if (mg_value_get_type(value1) != mg_value_get_type(value2)) { 110 return false; 111 } 112 final switch (mg_value_get_type(value1)) { 113 case mg_value_type.MG_VALUE_TYPE_NULL: 114 return true; 115 case mg_value_type.MG_VALUE_TYPE_BOOL: 116 return mg_value_bool(value1) == mg_value_bool(value2); 117 case mg_value_type.MG_VALUE_TYPE_INTEGER: 118 return mg_value_integer(value1) == mg_value_integer(value2); 119 case mg_value_type.MG_VALUE_TYPE_FLOAT: 120 return mg_value_float(value1) == mg_value_float(value2); 121 case mg_value_type.MG_VALUE_TYPE_STRING: 122 return Detail.convertString(mg_value_string(value1)) == 123 Detail.convertString(mg_value_string(value2)); 124 case mg_value_type.MG_VALUE_TYPE_LIST: 125 return Detail.areListsEqual(mg_value_list(value1), 126 mg_value_list(value2)); 127 case mg_value_type.MG_VALUE_TYPE_MAP: 128 return Detail.areMapsEqual(mg_value_map(value1), mg_value_map(value2)); 129 case mg_value_type.MG_VALUE_TYPE_NODE: 130 return Detail.areNodesEqual(mg_value_node(value1), 131 mg_value_node(value2)); 132 case mg_value_type.MG_VALUE_TYPE_RELATIONSHIP: 133 return Detail.areRelationshipsEqual(mg_value_relationship(value1), 134 mg_value_relationship(value2)); 135 case mg_value_type.MG_VALUE_TYPE_UNBOUND_RELATIONSHIP: 136 return Detail.areUnboundRelationshipsEqual( 137 mg_value_unbound_relationship(value1), 138 mg_value_unbound_relationship(value2)); 139 case mg_value_type.MG_VALUE_TYPE_PATH: 140 return Detail.arePathsEqual(mg_value_path(value1), 141 mg_value_path(value2)); 142 case mg_value_type.MG_VALUE_TYPE_DATE: 143 return Detail.areDatesEqual(mg_value_date(value1), 144 mg_value_date(value2)); 145 case mg_value_type.MG_VALUE_TYPE_TIME: 146 // return Detail.areTimesEqual(mg_value_time(value1), mg_value_time(value2)); 147 assert(0); 148 case mg_value_type.MG_VALUE_TYPE_LOCAL_TIME: 149 return Detail.areLocalTimesEqual(mg_value_local_time(value1), 150 mg_value_local_time(value2)); 151 case mg_value_type.MG_VALUE_TYPE_DATE_TIME: 152 // return Detail.areDateTimesEqual(mg_value_date_time(value1), mg_value_date_time(value2)); 153 assert(0); 154 case mg_value_type.MG_VALUE_TYPE_DATE_TIME_ZONE_ID: 155 /* 156 return Detail.areDateTimeZoneIdsEqual( 157 mg_value_date_time_zone_id(value1), 158 mg_value_date_time_zone_id(value2)); 159 */ 160 assert(0); 161 case mg_value_type.MG_VALUE_TYPE_LOCAL_DATE_TIME: 162 return Detail.areLocalDateTimesEqual(mg_value_local_date_time(value1), 163 mg_value_local_date_time(value2)); 164 case mg_value_type.MG_VALUE_TYPE_DURATION: 165 return Detail.areDurationsEqual(mg_value_duration(value1), 166 mg_value_duration(value2)); 167 case mg_value_type.MG_VALUE_TYPE_POINT_2D: 168 return Detail.arePoint2dsEqual(mg_value_point_2d(value1), 169 mg_value_point_2d(value2)); 170 case mg_value_type.MG_VALUE_TYPE_POINT_3D: 171 return Detail.arePoint3dsEqual(mg_value_point_3d(value1), 172 mg_value_point_3d(value2)); 173 case mg_value_type.MG_VALUE_TYPE_UNKNOWN: 174 assert(0, "comparing values of unknown types!"); 175 } 176 } 177 178 unittest { 179 auto nullValue1 = mg_value_make_null(); 180 auto nullValue2 = mg_value_make_null(); 181 auto stringValue1 = mg_value_make_string("Hello World"); 182 auto stringValue2 = mg_value_make_string("Hello World"); 183 184 assert(Detail.areValuesEqual(nullValue1, nullValue2)); 185 assert(!Detail.areValuesEqual(nullValue1, stringValue1)); 186 assert(Detail.areValuesEqual(stringValue1, stringValue2)); 187 188 auto boolValue1 = mg_value_make_bool(1); 189 auto boolValue2 = mg_value_make_bool(1); 190 assert(Detail.areValuesEqual(boolValue1, boolValue2)); 191 192 auto intValue1 = mg_value_make_integer(42); 193 auto intValue2 = mg_value_make_integer(42); 194 assert(Detail.areValuesEqual(intValue1, intValue2)); 195 196 auto floatValue1 = mg_value_make_float(3.14); 197 auto floatValue2 = mg_value_make_float(3.14); 198 assert(Detail.areValuesEqual(floatValue1, floatValue2)); 199 } 200 201 /// Compares two `mg_list`s. 202 @nogc static bool areListsEqual(const mg_list *list1, const mg_list *list2) { 203 assert(list1 != null); 204 assert(list2 != null); 205 if (list1 == list2) 206 return true; 207 if (mg_list_size(list1) != mg_list_size(list2)) 208 return false; 209 const uint len = mg_list_size(list1); 210 for (uint i = 0; i < len; ++i) { 211 if (!Detail.areValuesEqual(mg_list_at(list1, i), mg_list_at(list2, i))) 212 return false; 213 } 214 return true; 215 } 216 217 unittest { 218 auto list1 = mg_list_make_empty(1); 219 mg_list_append(list1, mg_value_make_string("Value1")); 220 auto list2 = mg_list_make_empty(1); 221 mg_list_append(list2, mg_value_make_string("Value1")); 222 223 auto listValue1 = mg_value_make_list(list1); 224 auto listValue2 = mg_value_make_list(list2); 225 assert(Detail.areValuesEqual(listValue1, listValue1)); 226 assert(Detail.areValuesEqual(listValue1, listValue2)); 227 228 auto list3 = mg_list_make_empty(2); 229 mg_list_append(list3, mg_value_make_string("Value1")); 230 mg_list_append(list3, mg_value_make_string("Value2")); 231 auto listValue3 = mg_value_make_list(list3); 232 assert(!Detail.areValuesEqual(listValue1, listValue3)); 233 234 auto list4 = mg_list_make_empty(2); 235 mg_list_append(list4, mg_value_make_string("Value1")); 236 mg_list_append(list4, mg_value_make_string("Value3")); 237 auto listValue4 = mg_value_make_list(list4); 238 assert(!Detail.areValuesEqual(listValue3, listValue4)); 239 } 240 241 /// Compares two `mg_map`s. 242 @nogc static bool areMapsEqual(const mg_map *map1, const mg_map *map2) { 243 assert(map1 != null); 244 assert(map2 != null); 245 if (map1 == map2) 246 return true; 247 if (mg_map_size(map1) != mg_map_size(map2)) 248 return false; 249 const uint len = mg_map_size(map1); 250 for (uint i = 0; i < len; ++i) { 251 const mg_string *key = mg_map_key_at(map1, i); 252 const mg_value *value1 = mg_map_value_at(map1, i); 253 const mg_value *value2 = 254 mg_map_at2(map2, mg_string_size(key), mg_string_data(key)); 255 if (value2 == null) 256 return false; 257 if (!Detail.areValuesEqual(value1, value2)) 258 return false; 259 } 260 return true; 261 } 262 263 unittest { 264 auto map1 = mg_map_make_empty(1); 265 mg_map_insert(map1, "key1", mg_value_make_string("Value1")); 266 auto map2 = mg_map_make_empty(1); 267 mg_map_insert(map2, "key1", mg_value_make_string("Value1")); 268 269 auto mapValue1 = mg_value_make_map(map1); 270 auto mapValue2 = mg_value_make_map(map2); 271 assert(Detail.areValuesEqual(mapValue1, mapValue2)); 272 assert(Detail.areValuesEqual(mapValue1, mapValue1)); 273 274 auto map3 = mg_map_make_empty(2); 275 mg_map_insert(map3, "key1", mg_value_make_string("Value1")); 276 mg_map_insert(map3, "key2", mg_value_make_string("Value2")); 277 auto mapValue3 = mg_value_make_map(map3); 278 assert(!Detail.areValuesEqual(mapValue1, mapValue3)); 279 280 auto map4 = mg_map_make_empty(2); 281 mg_map_insert(map4, "key1", mg_value_make_string("Value1")); 282 mg_map_insert(map4, "key3", mg_value_make_string("Value3")); 283 auto mapValue4 = mg_value_make_map(map4); 284 assert(!Detail.areValuesEqual(mapValue3, mapValue4)); 285 286 auto map5 = mg_map_make_empty(2); 287 mg_map_insert(map5, "key1", mg_value_make_string("Value1")); 288 mg_map_insert(map5, "key2", mg_value_make_string("Value3")); 289 auto mapValue5 = mg_value_make_map(map5); 290 assert(!Detail.areValuesEqual(mapValue3, mapValue5)); 291 } 292 293 /// Compares two nodes for equality. 294 /// Params: node1 = first node to compare 295 /// node2 = second node to compare 296 /// Return: `true` if both nodes are equal, `false` otherwise 297 @nogc static bool areNodesEqual(const mg_node *node1, const mg_node *node2) { 298 assert(node1 != null); 299 assert(node2 != null); 300 if (node1 == node2) 301 return true; 302 if (mg_node_id(node1) != mg_node_id(node2)) 303 return false; 304 if (mg_node_label_count(node1) != mg_node_label_count(node2)) 305 return false; 306 immutable label_count = mg_node_label_count(node1); 307 for (uint i = 0; i < label_count; ++i) { 308 if (Detail.convertString(mg_node_label_at(node1, i)) != Detail.convertString(mg_node_label_at(node2, i))) 309 return false; 310 } 311 return Detail.areMapsEqual(mg_node_properties(node1), mg_node_properties(node2)); 312 } // areNodesEqual() 313 314 unittest { 315 auto label1 = mg_string_make("label1"); 316 auto map1 = mg_map_make_empty(1); 317 mg_map_insert(map1, "key1", mg_value_make_string("value1")); 318 auto node1 = mg_node_make(1, 1, &label1, map1); 319 auto nodeValue1 = mg_value_make_node(node1); 320 assert(Detail.areValuesEqual(nodeValue1, nodeValue1)); 321 322 auto node2 = mg_node_make(2, 1, &label1, map1); 323 auto nodeValue2 = mg_value_make_node(node2); 324 assert(!Detail.areValuesEqual(nodeValue1, nodeValue2)); 325 326 auto label2 = mg_string_make("label2"); 327 mg_string** labels = cast(mg_string**)[ label1, label2 ]; 328 auto node3 = mg_node_make(1, 2, labels, map1); 329 auto nodeValue3 = mg_value_make_node(node3); 330 assert(!Detail.areValuesEqual(nodeValue1, nodeValue3)); 331 332 const label3 = mg_string_make("label3"); 333 mg_string** labels2 = cast(mg_string**)[ label1, label3 ]; 334 auto node4 = mg_node_make(1, 2, labels2, map1); 335 auto nodeValue4 = mg_value_make_node(node4); 336 assert(!Detail.areValuesEqual(nodeValue3, nodeValue4)); 337 338 labels2[1] = label2; 339 auto node5 = mg_node_make(1, 2, labels2, map1); 340 auto nodeValue5 = mg_value_make_node(node5); 341 assert(Detail.areValuesEqual(nodeValue3, nodeValue5)); 342 } 343 344 /// Compares two `mg_relationship`s. 345 @nogc static bool areRelationshipsEqual(const mg_relationship *rel1, 346 const mg_relationship *rel2) { 347 assert(rel1 != null); 348 assert(rel2 != null); 349 if (rel1 == rel2) 350 return true; 351 if (mg_relationship_id(rel1) != mg_relationship_id(rel2)) 352 return false; 353 if (mg_relationship_start_id(rel1) != mg_relationship_start_id(rel2)) 354 return false; 355 if (mg_relationship_end_id(rel1) != mg_relationship_end_id(rel2)) 356 return false; 357 if (Detail.convertString(mg_relationship_type(rel1)) != 358 Detail.convertString(mg_relationship_type(rel2))) 359 return false; 360 return Detail.areMapsEqual(mg_relationship_properties(rel1), 361 mg_relationship_properties(rel2)); 362 } 363 364 unittest { 365 auto relType1 = mg_string_make("Rel1"); 366 auto props1 = mg_map_make_empty(1); 367 mg_map_insert(props1, "key1", mg_value_make_string("Value1")); 368 auto rel1 = mg_relationship_make(1, 100, 101, relType1, props1); 369 auto relValue1 = mg_value_make_relationship(rel1); 370 371 auto relType2 = mg_string_make("Rel1"); 372 auto props2 = mg_map_make_empty(1); 373 mg_map_insert(props2, "key1", mg_value_make_string("Value1")); 374 auto rel2 = mg_relationship_make(1, 100, 101, relType2, props2); 375 auto relValue2 = mg_value_make_relationship(rel2); 376 377 assert(Detail.areValuesEqual(relValue1, relValue2)); 378 rel2.id = 2; 379 assert(!Detail.areValuesEqual(relValue1, relValue2)); 380 rel2.id = rel1.id; 381 rel2.start_id = 42; 382 assert(!Detail.areValuesEqual(relValue1, relValue2)); 383 rel2.id = rel1.id; 384 rel2.start_id = rel1.start_id; 385 rel2.end_id = 42; 386 assert(!Detail.areValuesEqual(relValue1, relValue2)); 387 auto relType3 = mg_string_make("Rel3"); 388 auto rel3 = mg_relationship_make(1, 100, 101, relType3, props2); 389 auto relValue3 = mg_value_make_relationship(rel3); 390 assert(!Detail.areValuesEqual(relValue1, relValue3)); 391 } 392 393 /// Compares two `mg_unbound_relationship`s. 394 @nogc static bool areUnboundRelationshipsEqual(const mg_unbound_relationship *rel1, 395 const mg_unbound_relationship *rel2) { 396 assert(rel1 != null); 397 assert(rel2 != null); 398 if (rel1 == rel2) 399 return true; 400 if (mg_unbound_relationship_id(rel1) != mg_unbound_relationship_id(rel2)) 401 return false; 402 if (Detail.convertString(mg_unbound_relationship_type(rel1)) != 403 Detail.convertString(mg_unbound_relationship_type(rel2))) 404 return false; 405 return Detail.areMapsEqual(mg_unbound_relationship_properties(rel1), 406 mg_unbound_relationship_properties(rel2)); 407 } 408 409 unittest { 410 auto relType1 = mg_string_make("Rel1"); 411 auto props1 = mg_map_make_empty(1); 412 mg_map_insert(props1, "key1", mg_value_make_string("Value1")); 413 auto rel1 = mg_unbound_relationship_make(1, relType1, props1); 414 auto relValue1 = mg_value_make_unbound_relationship(rel1); 415 416 auto relType2 = mg_string_make("Rel1"); 417 auto props2 = mg_map_make_empty(1); 418 mg_map_insert(props2, "key1", mg_value_make_string("Value1")); 419 auto rel2 = mg_unbound_relationship_make(1, relType2, props2); 420 auto relValue2 = mg_value_make_unbound_relationship(rel2); 421 422 assert(Detail.areValuesEqual(relValue1, relValue2)); 423 rel2.id = 2; 424 assert(!Detail.areValuesEqual(relValue1, relValue2)); 425 auto relType3 = mg_string_make("Rel3"); 426 auto rel3 = mg_unbound_relationship_make(1, relType3, props2); 427 auto relValue3 = mg_value_make_unbound_relationship(rel3); 428 assert(!Detail.areValuesEqual(relValue1, relValue3)); 429 } 430 431 /// Compares two `mg_path`s. 432 @nogc static bool arePathsEqual(const mg_path *path1, const mg_path *path2) { 433 assert(path1 != null); 434 assert(path2 != null); 435 if (path1 == path2) 436 return true; 437 if (mg_path_length(path1) != mg_path_length(path2)) 438 return false; 439 const uint len = mg_path_length(path1); 440 for (uint i = 0; i < len; ++i) { 441 if (!Detail.areNodesEqual(mg_path_node_at(path1, i), 442 mg_path_node_at(path2, i))) { 443 return false; 444 } 445 if (!Detail.areUnboundRelationshipsEqual( 446 mg_path_relationship_at(path1, i), 447 mg_path_relationship_at(path2, i))) { 448 return false; 449 } 450 if (mg_path_relationship_reversed_at(path1, i) != 451 mg_path_relationship_reversed_at(path2, i)) { 452 return false; 453 } 454 } 455 return Detail.areNodesEqual(mg_path_node_at(path1, len), 456 mg_path_node_at(path2, len)); 457 } 458 459 unittest { 460 461 mg_node*[6] nodes; 462 nodes[0] = mg_node_make(1, 0, null, mg_map_make_empty(0)); 463 nodes[1] = mg_node_make(2, 0, null, mg_map_make_empty(0)); 464 nodes[2] = mg_node_make(3, 0, null, mg_map_make_empty(0)); 465 nodes[3] = mg_node_make(4, 0, null, mg_map_make_empty(0)); 466 nodes[4] = mg_node_make(5, 0, null, mg_map_make_empty(0)); 467 nodes[5] = mg_node_make(6, 0, null, mg_map_make_empty(0)); 468 469 const auto seqs = [0L, 1L, 2L, 3L, 4L, 5L]; 470 471 mg_unbound_relationship*[6] rels; 472 rels[0] = mg_unbound_relationship_make(1, mg_string_make("Rel1"), mg_map_make_empty(0)); 473 rels[1] = mg_unbound_relationship_make(2, mg_string_make("Rel1"), mg_map_make_empty(0)); 474 rels[2] = mg_unbound_relationship_make(3, mg_string_make("Rel1"), mg_map_make_empty(0)); 475 rels[3] = mg_unbound_relationship_make(4, mg_string_make("Rel1"), mg_map_make_empty(0)); 476 rels[4] = mg_unbound_relationship_make(5, mg_string_make("Rel1"), mg_map_make_empty(0)); 477 rels[5] = mg_unbound_relationship_make(6, mg_string_make("Rel2"), mg_map_make_empty(0)); 478 479 auto path1 = mg_path_make(2u, cast(mg_node**)nodes, 1u, cast(mg_unbound_relationship**)rels, 480 2u, cast(const long*)seqs); 481 auto pathValue1 = mg_value_make_path(path1); 482 auto path2 = mg_path_make(2u, cast(mg_node**)nodes, 1u, cast(mg_unbound_relationship**)rels, 483 2u, cast(const long*)seqs); 484 auto pathValue2 = mg_value_make_path(path2); 485 486 assert(Detail.areValuesEqual(pathValue1, pathValue2)); 487 488 auto path3 = mg_path_make(4u, cast(mg_node**)nodes, 3u, cast(mg_unbound_relationship**)rels, 489 4u, cast(const long*)seqs); 490 auto pathValue3 = mg_value_make_path(path3); 491 492 assert(!Detail.areValuesEqual(pathValue1, pathValue3)); 493 494 auto path4 = mg_path_make(4u, cast(mg_node**)&nodes[1], 3u, cast(mg_unbound_relationship**)&rels[1], 495 4u, cast(const long*)&seqs[1]); 496 auto pathValue4 = mg_value_make_path(path4); 497 498 assert(!Detail.areValuesEqual(pathValue3, pathValue4)); 499 500 auto path5 = mg_path_make(4u, cast(mg_node**)&nodes[1], 3u, cast(mg_unbound_relationship**)&rels[2], 501 4u, cast(const long*)&seqs[1]); 502 auto pathValue5 = mg_value_make_path(path5); 503 504 assert(!Detail.areValuesEqual(pathValue4, pathValue5)); 505 506 // TODO: test path reversed at line 451 507 } 508 509 /// Compares two `mg_date`s. 510 @nogc static bool areDatesEqual(const mg_date *date1, const mg_date *date2) { 511 assert(date1 != null); 512 assert(date2 != null); 513 return mg_date_days(date1) == mg_date_days(date2); 514 } 515 516 /// Compares two `mg_time`s. 517 /* 518 @nogc static bool areTimesEqual(const mg_time *time1, const mg_time *time2) { 519 assert(time1 != null); 520 assert(time2 != null); 521 return mg_time_nanoseconds(time1) == mg_time_nanoseconds(time2) && 522 mg_time_tz_offset_seconds(time1) == mg_time_tz_offset_seconds(time2); 523 } 524 */ 525 526 /// Compares two `mg_local_time`s. 527 @nogc static bool areLocalTimesEqual(const mg_local_time *local_time1, 528 const mg_local_time *local_time2) { 529 assert(local_time1 != null); 530 assert(local_time2 != null); 531 return mg_local_time_nanoseconds(local_time1) == 532 mg_local_time_nanoseconds(local_time2); 533 } 534 535 unittest { 536 auto localTime1 = mg_local_time_make(4711); 537 auto localTimeValue1 = mg_value_make_local_time(localTime1); 538 auto localTime2 = mg_local_time_make(4711); 539 auto localTimeValue2 = mg_value_make_local_time(localTime2); 540 assert(Detail.areValuesEqual(localTimeValue1, localTimeValue2)); 541 } 542 543 /// Compares two `mg_date_time`s. 544 /* 545 @nogc static bool areDateTimesEqual(const mg_date_time *date_time1, 546 const mg_date_time *date_time2) { 547 assert(date_time1 != null); 548 assert(date_time2 != null); 549 return mg_date_time_seconds(date_time1) == mg_date_time_seconds(date_time2) && 550 mg_date_time_nanoseconds(date_time1) == 551 mg_date_time_nanoseconds(date_time2) && 552 mg_date_time_tz_offset_minutes(date_time1) == 553 mg_date_time_tz_offset_minutes(date_time2); 554 } 555 */ 556 557 /// Compares two `mg_date_time_zone`s. 558 /* 559 @nogc static bool areDateTimeZoneIdsEqual( 560 const mg_date_time_zone_id *date_time_zone_id1, 561 const mg_date_time_zone_id *date_time_zone_id2) { 562 assert(date_time_zone_id1 != null); 563 assert(date_time_zone_id2 != null); 564 return mg_date_time_zone_id_seconds(date_time_zone_id1) == 565 mg_date_time_zone_id_seconds(date_time_zone_id2) && 566 mg_date_time_zone_id_nanoseconds(date_time_zone_id1) == 567 mg_date_time_zone_id_nanoseconds(date_time_zone_id2) && 568 mg_date_time_zone_id_tz_id(date_time_zone_id1) == 569 mg_date_time_zone_id_tz_id(date_time_zone_id2); 570 } 571 */ 572 573 /// Compares two `mg_local_date_time`s. 574 @nogc static bool areLocalDateTimesEqual(const mg_local_date_time *local_date_time1, 575 const mg_local_date_time *local_date_time2) { 576 assert(local_date_time1 != null); 577 assert(local_date_time2 != null); 578 return mg_local_date_time_seconds(local_date_time1) == 579 mg_local_date_time_seconds(local_date_time2) && 580 mg_local_date_time_nanoseconds(local_date_time1) == 581 mg_local_date_time_nanoseconds(local_date_time2); 582 } 583 584 unittest { 585 auto dateTime1 = mg_local_date_time_make(100, 42); 586 auto dateTimeValue1 = mg_value_make_local_date_time(dateTime1); 587 auto dateTime2 = mg_local_date_time_make(100, 42); 588 auto dateTimeValue2 = mg_value_make_local_date_time(dateTime2); 589 assert(Detail.areValuesEqual(dateTimeValue1, dateTimeValue2)); 590 } 591 592 /// Compares two `mg_duration`s. 593 @nogc static bool areDurationsEqual(const mg_duration *duration1, 594 const mg_duration *duration2) { 595 assert(duration1 != null); 596 assert(duration2 != null); 597 return mg_duration_months(duration1) == mg_duration_months(duration2) && 598 mg_duration_days(duration1) == mg_duration_days(duration2) && 599 mg_duration_seconds(duration1) == mg_duration_seconds(duration2) && 600 mg_duration_nanoseconds(duration1) == 601 mg_duration_nanoseconds(duration2); 602 } 603 604 unittest { 605 auto dur1 = mg_duration_make(0, 7, 100, 42); 606 auto durValue1 = mg_value_make_duration(dur1); 607 auto dur2 = mg_duration_make(0, 7, 100, 42); 608 auto durValue2 = mg_value_make_duration(dur2); 609 assert(Detail.areValuesEqual(durValue1, durValue2)); 610 } 611 612 /// Compares two `mg_point_2d`s. 613 @nogc static bool arePoint2dsEqual(const mg_point_2d *point_2d1, 614 const mg_point_2d *point_2d2) { 615 assert(point_2d1 != null); 616 assert(point_2d2 != null); 617 return mg_point_2d_srid(point_2d1) == mg_point_2d_srid(point_2d2) && 618 mg_point_2d_x(point_2d1) == mg_point_2d_x(point_2d2) && 619 mg_point_2d_y(point_2d1) == mg_point_2d_y(point_2d2); 620 } 621 622 unittest { 623 auto point1 = mg_point_2d_alloc(&mg_system_allocator); 624 point1.srid = 1; 625 point1.x = 100; 626 point1.y = 100; 627 auto pointValue1 = mg_value_make_point_2d(point1); 628 629 auto point2 = mg_point_2d_alloc(&mg_system_allocator); 630 point2.srid = 1; 631 point2.x = 100; 632 point2.y = 100; 633 auto pointValue2 = mg_value_make_point_2d(point2); 634 635 assert(Detail.areValuesEqual(pointValue1, pointValue2)); 636 } 637 638 /// Compares two `mg_point_3d`s. 639 @nogc static bool arePoint3dsEqual(const mg_point_3d *point_3d1, 640 const mg_point_3d *point_3d2) { 641 assert(point_3d1 != null); 642 assert(point_3d2 != null); 643 return mg_point_3d_srid(point_3d1) == mg_point_3d_srid(point_3d2) && 644 mg_point_3d_x(point_3d1) == mg_point_3d_x(point_3d2) && 645 mg_point_3d_y(point_3d1) == mg_point_3d_y(point_3d2) && 646 mg_point_3d_z(point_3d1) == mg_point_3d_z(point_3d2); 647 } 648 649 unittest { 650 auto point1 = mg_point_3d_alloc(&mg_system_allocator); 651 point1.srid = 1; 652 point1.x = 100; 653 point1.y = 100; 654 point1.z = 100; 655 auto pointValue1 = mg_value_make_point_3d(point1); 656 657 auto point2 = mg_point_3d_alloc(&mg_system_allocator); 658 point2.srid = 1; 659 point2.x = 100; 660 point2.y = 100; 661 point2.z = 100; 662 auto pointValue2 = mg_value_make_point_3d(point2); 663 664 assert(Detail.areValuesEqual(pointValue1, pointValue2)); 665 } 666 }