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 copy of `other` unbound relationship.
13 	this(inout ref UnboundRelationship other) {
14 		this(mg_unbound_relationship_copy(other.ptr));
15 	}
16 
17 	/// Create a unbound relationship from a Value.
18 	this(inout ref Value value) {
19 		assert(value.type == Type.UnboundRelationship);
20 		this(mg_unbound_relationship_copy(mg_value_unbound_relationship(value.ptr)));
21 	}
22 
23 	/// Return a printable string representation of this unbound relationship.
24 	const (string) toString() const {
25 		return type;
26 	}
27 
28 	/// Compares this unbound relationship with `other`.
29 	/// Return: true if same, false otherwise.
30 	bool opEquals(const ref UnboundRelationship other) const {
31 		return Detail.areUnboundRelationshipsEqual(ptr, other.ptr);
32 	}
33 
34 	/// Returns the unbound relationship id.
35 	const (long) id() const {
36 		assert(ptr != null);
37 		return mg_unbound_relationship_id(ptr);
38 	}
39 
40 	/// Returns the unbound relationship type.
41 	const (string) type() const {
42 		assert(ptr != null);
43 		return Detail.convertString(mg_unbound_relationship_type(ptr));
44 	}
45 
46 	/// Returns the unbound relationship properties.
47 	const (Map) properties() const {
48 		assert(ptr != null);
49 		return Map(mg_unbound_relationship_properties(ptr));
50 	}
51 
52 	this(this) {
53 		if (ptr_)
54 			ptr_ = mg_unbound_relationship_copy(ptr_);
55 	}
56 
57 	~this() {
58 		if (ptr_)
59 			mg_unbound_relationship_destroy(ptr_);
60 	}
61 
62 package:
63 	/// Create a Unbound Relationship using the given `mg_unbound_relationship`.
64 	this(mg_unbound_relationship *ptr) {
65 		assert(ptr != null);
66 		ptr_ = ptr;
67 	}
68 
69 	/// Create a Unbound Relationship from a copy of the given `mg_unbound_relationship`.
70 	this(const mg_unbound_relationship *ptr) {
71 		assert(ptr != null);
72 		this(mg_unbound_relationship_copy(ptr));
73 	}
74 
75 	const (mg_unbound_relationship *) ptr() const { return ptr_; }
76 
77 private:
78 	mg_unbound_relationship *ptr_;
79 }
80 
81 unittest {
82 	import testutils : connectContainer, createTestData, deleteTestData;
83 	import memgraph : Client, Type, Value, Node, Relationship;
84 	import std.conv : to;
85 
86 	auto client = connectContainer();
87 	assert(client);
88 
89 	deleteTestData(client);
90 
91 	createTestData(client);
92 
93 	// TODO: fix unit test, ie. use unbound relationship, e.g. via Path
94 	auto res = client.execute(
95 					"MATCH (a:Person)-[r:IS_MANAGER]-(b:Person) " ~
96 						"RETURN a, r, b;");
97 	assert(res, client.error);
98 	foreach (c; res) {
99 		assert(c[0].type == Type.Node);
100 		assert(c[1].type == Type.Relationship);
101 		assert(c[2].type == Type.Node);
102 		auto a = to!Node(c[0]);
103 		auto r = to!Relationship(c[1]);
104 		auto b = to!Node(c[2]);
105 		assert(to!string(a) == to!string(c[0]));
106 		assert(to!string(r) == to!string(c[1]));
107 		assert(to!string(b) == to!string(c[2]));
108 
109 		const r2 = r;
110 		assert(r2 == r);
111 
112 		const r3 = Relationship(r);
113 		assert(r3 == r);
114 
115 		const r4 = Relationship(r.ptr);
116 		assert(r4 == r);
117 
118 		assert(r.id == r2.id);
119 		assert(r.startId == r2.startId);
120 		assert(r.endId == r2.endId);
121 		assert(r.properties == r2.properties);
122 
123 		auto v = Value(r);
124 		assert(v == r);
125 		assert(r == v);
126 		assert(to!string(v) == to!string(r));
127 	}
128 	assert(to!string(res.columns) == `["a", "r", "b"]`);
129 }