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 copy of `other` relationship.
13 	this(inout ref Relationship other) {
14 		this(mg_relationship_copy(other.ptr));
15 	}
16 
17 	/// Create a relationship from a Value.
18 	this(inout ref Value value) {
19 		assert(value.type == Type.Relationship);
20 		this(mg_relationship_copy(mg_value_relationship(value.ptr)));
21 	}
22 
23 	/// Return a printable string representation of this relationship.
24 	const (string) toString() const {
25 		return type();
26 	}
27 
28 	/// Compares this relationship with `other`.
29 	/// Return: true if same, false otherwise.
30 	bool opEquals(const ref Relationship other) const {
31 		return Detail.areRelationshipsEqual(ptr_, other.ptr_);
32 	}
33 
34 	/// Returns the relationship id.
35 	const (long) id() const {
36 		return mg_relationship_id(ptr_);
37 	}
38 
39 	/// Returns the relationship start id.
40 	const (long) startId() const {
41 		return mg_relationship_start_id(ptr_);
42 	}
43 
44 	/// Returns the relationship end id.
45 	const (long) endId() const {
46 		return mg_relationship_end_id(ptr_);
47 	}
48 
49 	/// Returns the relationship type.
50 	const (string) type() const {
51 		return Detail.convertString(mg_relationship_type(ptr_));
52 	}
53 
54 	/// Returns the relationship properties.
55 	const (Map) properties() const {
56 		return Map(mg_relationship_properties(ptr_));
57 	}
58 
59 	this(this) {
60 		if (ptr_)
61 			ptr_ = mg_relationship_copy(ptr_);
62 	}
63 
64 	~this() {
65 		if (ptr_)
66 			mg_relationship_destroy(ptr_);
67 	}
68 
69 package:
70 	/// Create a Relationship using the given `mg_relationship`.
71 	this(mg_relationship *ptr) {
72 		assert(ptr != null);
73 		ptr_ = ptr;
74 	}
75 
76 	/// Create a Relationship from a copy of the given `mg_relationship`.
77 	this(const mg_relationship *const_ptr) {
78 		assert(const_ptr != null);
79 		this(mg_relationship_copy(const_ptr));
80 	}
81 
82 	const (mg_relationship *) ptr() const { return ptr_; }
83 
84 private:
85 	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 v = Value(r);
130 		assert(v == r);
131 		assert(r == v);
132 		assert(v == c[1]);
133 
134 		const r5 = Relationship(r3);
135 		assert(r5 == r3);
136 	}
137 	assert(to!string(res.columns) == `["a", "r", "b"]`);
138 }