1 /// Provides a wrapper for a `mg_duration`. Uses `core.time.Duration` internally.
2 module memgraph.duration;
3 
4 import memgraph.mgclient, memgraph.detail, memgraph.value, memgraph.enums;
5 
6 import ct = core.time;
7 
8 /// Represents a temporal amount which captures the difference in time
9 /// between two instants.
10 /// Duration is defined with months, days, seconds, and nanoseconds.
11 /// Note: Duration can be negative.
12 /// Uses a `core.time.Duration` internally.
13 struct Duration {
14   /// Create a shallow copy of `other` Duration.
15   @nogc this(inout ref Duration other) {
16     this(other.ptr);
17   }
18 
19   /// Create a duration from a Value.
20   @nogc this(inout ref Value value) {
21     assert(value.type == Type.Duration);
22     this(mg_value_duration(value.ptr));
23   }
24 
25   /// Return a printable string representation of this duration.
26   string toString() const { return duration_.toString; }
27 
28   /// Returns the months part of the temporal amount.
29   @nogc auto months() const { return 0; } // See note in ctor.
30 
31   /// Returns the days part of the temporal amount.
32   @nogc auto days() const { return duration_.total!"days"; }
33 
34   /// Returns the seconds part of the temporal amount.
35   @nogc auto seconds() const { return (duration_ - ct.days(duration_.total!"days")).total!"seconds"; }
36 
37   /// Returns the nanoseconds part of the temporal amount.
38   @nogc auto nanoseconds() const { return (duration_ - ct.seconds(duration_.total!"seconds")).total!"nsecs"; }
39 
40 package:
41   /// Create a Duration using the given `mg_duration`.
42   @nogc this(const mg_duration *ptr) {
43     assert(ptr != null);
44     ptr_ = ptr;
45     // Note: there is no "months" duration in core.time because months have variable number of days
46     assert(mg_duration_months(ptr) == 0);
47     duration_ = ct.days(mg_duration_days(ptr)) +
48                 ct.seconds(mg_duration_seconds(ptr)) +
49                 ct.nsecs(mg_duration_nanoseconds(ptr));
50   }
51 
52   /// Return pointer to internal `mg_duration`.
53   @nogc auto ptr() inout {
54     return ptr_;
55   }
56 
57 private:
58   const mg_duration *ptr_;
59   ct.Duration duration_;
60   alias duration_ this;
61 } // struct Duration
62 
63 unittest {
64   import testutils : connectContainer;
65   import std.algorithm : count;
66   import std.conv : to;
67 
68   auto client = connectContainer();
69   assert(client);
70 
71   auto result = client.execute(`return duration('P9DT11H23M7S');`);
72   assert(result, client.error);
73   foreach (r; result) {
74     assert(r.length == 1);
75     assert(r[0].type() == Type.Duration);
76     const d = to!Duration(r[0]);
77     assert(d.toString == "1 week, 2 days, 11 hours, 23 minutes, and 7 secs", d.toString);
78     assert(d.months == 0);
79     assert(d.days == 9);
80     assert(d.seconds == 11*60*60+23*60+7);
81     assert(d.nanoseconds == 0);
82   }
83 }
84 
85 unittest {
86   import std.conv : to;
87   import memgraph.enums;
88 
89   auto du = mg_duration_make(0, 5, 42, 230_000);
90   assert(du != null);
91 
92   auto d = Duration(du);
93   assert(d.months == 0);
94   assert(d.days == 5);
95   assert(d.seconds == 42);
96   assert(d.nanoseconds == 230_000);
97 
98   const d1 = d;
99   assert(d1 == d);
100 
101   assert(to!string(d) == "5 days, 42 secs, and 230 μs", to!string(d));
102   assert(d.toString == "5 days, 42 secs, and 230 μs", to!string(d));
103 
104   const ct.Duration dur = d;
105   assert(dur.toString == "5 days, 42 secs, and 230 μs", to!string(d));
106 
107   auto v = Value(mg_value_make_duration(du));
108   assert(to!string(v) == "5 days, 42 secs, and 230 μs", to!string(v));
109 }