1 /// Provides a wrapper around a `Relationship`.
2 module memgraph.relationship;
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 /// Consists of a unique identifier (within the scope of its origin graph),
9 /// identifiers for the start and end nodes of that relationship, a type and a
10 /// map of properties. A relationship owns its type string and property map.
11 struct Relationship {
12   /// Create a shallow copy of `other` relationship.
13   @nogc this(inout ref Relationship other) {
14     this(other.ptr);
15   }
16 
17   /// Create a relationship from a Value.
18   @nogc this(inout ref Value value) {
19     assert(value.type == Type.Relationship);
20     this(mg_value_relationship(value.ptr));
21   }
22 
23   /// Return a printable string representation of this 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(to!string(startId));
30     str.put(")-[");
31     str.put(type());
32     str.put("]-(");
33     str.put(to!string(endId));
34     str.put(")");
35     return str.data;
36   }
37 
38   /// Compares this relationship with `other`.
39   /// Return: true if same, false otherwise.
40   @nogc auto opEquals(const ref Relationship other) const {
41     return Detail.areRelationshipsEqual(ptr_, other.ptr_);
42   }
43 
44   /// Return the hash code for this relationship.
45   size_t toHash() const nothrow @safe {
46     return cast(ulong)ptr_;
47   }
48 
49   /// Returns the relationship id.
50   @nogc auto id() const {
51     return mg_relationship_id(ptr_);
52   }
53 
54   /// Returns the relationship start id.
55   @nogc auto startId() const {
56     return mg_relationship_start_id(ptr_);
57   }
58 
59   /// Returns the relationship end id.
60   @nogc auto endId() const {
61     return mg_relationship_end_id(ptr_);
62   }
63 
64   /// Returns the relationship type.
65   @nogc auto type() const {
66     return Detail.convertString(mg_relationship_type(ptr_));
67   }
68 
69   /// Returns the relationship properties.
70   @nogc auto properties() const {
71     return Map(mg_relationship_properties(ptr_));
72   }
73 
74 package:
75   /// Create a Relationship using the given `mg_relationship` pointer.
76   @nogc this(const mg_relationship *ptr) {
77     assert(ptr != null);
78     ptr_ = ptr;
79   }
80 
81   /// Return pointer to internal mg_relationship.
82   @nogc auto ptr() inout { return ptr_; }
83 
84 private:
85   const mg_relationship *ptr_;
86 }
87 
88 unittest {
89   import testutils : connectContainer, createTestData, deleteTestData;
90   import memgraph : Client, Type, Value, Node, Relationship;
91   import std.conv : to;
92 
93   auto client = connectContainer();
94   assert(client);
95 
96   deleteTestData(client);
97 
98   createTestData(client);
99 
100   auto res = client.execute(
101           "MATCH (a:Person)-[r:IS_MANAGER]->(b:Person) " ~
102             "RETURN a, r, b;");
103   assert(res, client.error);
104   foreach (c; res) {
105     assert(c[0].type == Type.Node);
106     assert(c[1].type == Type.Relationship);
107     assert(c[2].type == Type.Node);
108     auto a = to!Node(c[0]);
109     auto r = to!Relationship(c[1]);
110     auto b = to!Node(c[2]);
111     assert(to!string(a) == to!string(c[0]));
112     assert(to!string(r) == to!string(c[1]));
113     assert(to!string(b) == to!string(c[2]));
114 
115     const r2 = r;
116     assert(r2 == r);
117 
118     const r3 = Relationship(r);
119     assert(r3 == r);
120 
121     const r4 = Relationship(r.ptr);
122     assert(r4 == r);
123 
124     assert(r.id == r2.id);
125     assert(r.startId == r2.startId);
126     assert(r.endId == r2.endId);
127     assert(r.properties == r2.properties);
128 
129     const r5 = Relationship(r3);
130     assert(r5 == r3);
131 
132     assert(cast(ulong)r.ptr == r.toHash);
133   }
134   assert(to!string(res.columns) == `["a", "r", "b"]`);
135 }