1 /// Provides a wrapper around a `mg_duration`.
2 module memgraph.duration;
3 
4 import memgraph.mgclient, memgraph.detail, memgraph.value, memgraph.enums;
5 
6 /// Represents a temporal amount which captures the difference in time
7 /// between two instants.
8 ///
9 /// Duration is defined with months, days, seconds, and nanoseconds.
10 /// Note: Duration can be negative.
11 struct Duration {
12 
13 	/// Create a copy of `other` duration.
14 	this(inout ref Duration other) {
15 		this(mg_duration_copy(other.ptr));
16 	}
17 
18 	/// Create a duration from a Value.
19 	this(inout ref Value value) {
20 		assert(value.type == Type.Duration);
21 		this(mg_duration_copy(mg_value_duration(value.ptr)));
22 	}
23 
24 	/// Assigns a duration to another. The target of the assignment gets detached from
25 	/// whatever duration it was attached to, and attaches itself to the new duration.
26 	ref Duration opAssign(Duration rhs) @safe return {
27 		import std.algorithm.mutation : swap;
28 		swap(this, rhs);
29 		return this;
30 	}
31 
32 	/// Return a printable string representation of this duration.
33 	const (string) toString() const {
34 		import std.conv : to;
35 		return to!string(months) ~ " " ~ to!string(days) ~ " " ~ to!string(seconds) ~ " " ~ to!string(nanoseconds);
36 	}
37 
38 	/// Compares this duration with `other`.
39 	/// Return: true if same, false otherwise.
40 	bool opEquals(const ref Duration other) const {
41 		return Detail.areDurationsEqual(ptr_, other.ptr);
42 	}
43 
44 	/// Returns the months part of the temporal amount.
45 	const (long) months() const { return mg_duration_months(ptr_); }
46 
47 	/// Returns the days part of the temporal amount.
48 	const (long) days() const { return mg_duration_days(ptr_); }
49 
50 	/// Returns the seconds part of the temporal amount.
51 	const (long) seconds() const { return mg_duration_seconds(ptr_); }
52 
53 	/// Returns the nanoseconds part of the temporal amount.
54 	const (long) nanoseconds() const { return mg_duration_nanoseconds(ptr_); }
55 
56 	this(this) {
57 		if (ptr_)
58 			ptr_ = mg_duration_copy(ptr_);
59 	}
60 
61 	@safe @nogc ~this() {
62 		if (ptr_)
63 			mg_duration_destroy(ptr_);
64 	}
65 
66 package:
67 	/// Create a Duration using the given `mg_duration`.
68 	this(mg_duration *ptr) @trusted {
69 		assert(ptr != null);
70 		ptr_ = ptr;
71 	}
72 
73 	/// Create a Duration from a copy of the given `mg_duration`.
74 	this(const mg_duration *ptr) {
75 		assert(ptr != null);
76 		this(mg_duration_copy(ptr));
77 	}
78 
79 	const (mg_duration *) ptr() const { return ptr_; }
80 
81 private:
82 	mg_duration *ptr_;
83 }
84 
85 unittest {
86 	import std.conv : to;
87 	import memgraph.enums;
88 
89 	auto tm = mg_duration_alloc(&mg_system_allocator);
90 	assert(tm != null);
91 	tm.months = 3;
92 	tm.days = 10;
93 	tm.seconds = 42;
94 	tm.nanoseconds = 23;
95 
96 	auto t = Duration(tm);
97 	assert(t.months == 3);
98 	assert(t.days == 10);
99 	assert(t.seconds == 42);
100 	assert(t.nanoseconds == 23);
101 
102 	const t1 = t;
103 	assert(t1 == t);
104 
105 	assert(to!string(t) == "3 10 42 23");
106 
107 	auto t2 = Duration(t.ptr);
108 	assert(t2 == t);
109 
110 	const t3 = Duration(t2);
111 	assert(t3 == t);
112 
113 	const v = Value(t);
114 	const t4 = Duration(v);
115 	assert(t4 == t);
116 	assert(v == t);
117 	assert(to!string(v) == to!string(t));
118 
119 	t2 = t;
120 	assert(t2 == t);
121 
122 	const v1 = Value(t2);
123 	assert(v1.type == Type.Duration);
124 	const v2 = Value(t2);
125 	assert(v2.type == Type.Duration);
126 
127 	assert(v1 == v2);
128 
129 	const t5 = Duration(t3);
130 	assert(t5 == t3);
131 }