1 /// Provides a wrapper around a `UnboundRelationship`.
2 module memgraph.unboundrelationship;
3 
4 import memgraph.mgclient, memgraph.detail, memgraph.map, memgraph.value, memgraph.enums;
5 
6 /// Represents a relationship from a labeled property graph.
7 ///
8 /// Like `mg_relationship`, but without identifiers for start and end nodes.
9 /// Mainly used as a supporting type for `mg_path`. An unbound relationship
10 /// owns its type string and property map.
11 struct UnboundRelationship {
12   /// Create a shallow copy of `other` unbound relationship.
13   @nogc this(inout ref UnboundRelationship other) {
14     this(other.ptr);
15   }
16 
17   /// Create a unbound relationship from a Value.
18   @nogc this(inout ref Value value) {
19     assert(value.type == Type.UnboundRelationship);
20     this(mg_value_unbound_relationship(value.ptr));
21   }
22 
23   /// Return a printable string representation of this unbound relationship.
24   string toString() const {
25     import std.array : appender;
26     import std.conv : to;
27     auto str = appender!string;
28     str.put("[");
29     str.put(type());
30     str.put("]");
31     return str.data;
32   }
33 
34   /// Compares this unbound relationship with `other`.
35   /// Return: true if same, false otherwise.
36   @nogc auto opEquals(const ref UnboundRelationship other) const {
37     return Detail.areUnboundRelationshipsEqual(ptr, other.ptr);
38   }
39 
40   /// Return the hash code for this unbound relationship.
41   size_t toHash() const nothrow @safe {
42     return cast(ulong)ptr_;
43   }
44 
45   /// Returns the unbound relationship id.
46   @nogc auto id() const {
47     return mg_unbound_relationship_id(ptr);
48   }
49 
50   /// Returns the unbound relationship type.
51   @nogc auto type() const {
52     return Detail.convertString(mg_unbound_relationship_type(ptr));
53   }
54 
55   /// Returns the unbound relationship properties.
56   @nogc auto properties() const {
57     return Map(mg_unbound_relationship_properties(ptr));
58   }
59 
60 package:
61   /// Create a Unbound Relationship using the given `mg_unbound_relationship` pointer.
62   @nogc this(const mg_unbound_relationship *ptr) {
63     assert(ptr != null);
64     ptr_ = ptr;
65   }
66 
67   @nogc auto ptr() inout { return ptr_; }
68 
69 private:
70   const mg_unbound_relationship *ptr_;
71 } // struct UnboundRelationship
72 
73 unittest {
74   import testutils : connectContainer, createTestData, deleteTestData;
75   import memgraph : Client, Type, Value, Node, UnboundRelationship, Path;
76   import std.conv : to;
77 
78   auto client = connectContainer();
79   assert(client);
80 
81   deleteTestData(client);
82 
83   createTestData(client);
84 
85   auto res = client.execute(
86           "MATCH p = ()-[*3]->() " ~
87             "RETURN p;");
88   assert(res, client.error);
89   foreach (c; res) {
90     assert(c[0].type == Type.Path);
91     const path = to!Path(c[0]);
92     assert(to!string(path) == to!string(c[0]));
93 
94     immutable auto expectedNames = [ "John", "Peter", "Valery", "Oløf" ];
95     foreach (i; 0..path.length+1) {
96       const n = path.getNodeAt(to!uint(i));
97       const p = n.properties;
98       assert(to!string(p["name"]) == expectedNames[i], to!string(p["name"]));
99       if (i < path.length) {
100         auto r = path.getRelationshipAt(to!uint(i));
101         assert(to!string(r) == "[" ~ r.type ~ "]");
102       }
103     }
104   }
105   assert(to!string(res.columns) == `["p"]`);
106 }
107 
108 unittest {
109   auto r = UnboundRelationship(mg_unbound_relationship_make(1, mg_string_make("rel"), mg_map_make_empty(0)));
110   auto v = Value(mg_value_make_unbound_relationship(mg_unbound_relationship_copy(r.ptr)));
111   const r2 = UnboundRelationship(v);
112   assert(r == r2);
113   assert(r == v);
114 
115   import std.conv : to;
116   assert(to!string(v) == "[rel]", to!string(v));
117 
118   assert(cast(ulong)r.ptr == r.toHash);
119 }