1 /// Provides a wrapper for a `mg_date`. Uses `std.datetime.date.Date` internally.
2 module memgraph.date;
3 
4 import memgraph.mgclient, memgraph.detail, memgraph.value, memgraph.enums;
5 import sd = std.datetime.date;
6 import ct = core.time;
7 
8 /// Represents a date.
9 /// Date is defined with number of days since the Unix epoch.
10 /// Uses a `std.datetime.date.Date` internally.
11 struct Date {
12   /// Create a shallow copy of `other` Date.
13   @nogc this(inout ref Date other) {
14     this(other.ptr_);
15   }
16 
17   /// Create a date from a Value.
18   @nogc this(inout ref Value value) {
19     assert(value.type == Type.Date);
20     this(mg_value_date(value.ptr));
21   }
22 
23   /// Compares this date with `other`.
24   /// Return: true if same, false otherwise.
25   @nogc auto opEquals(const ref Date other) const {
26     return Detail.areDatesEqual(ptr_, other.ptr_);
27   }
28 
29   /// Return the hash code for this date.
30   size_t toHash() const nothrow @safe {
31     return cast(ulong)ptr_;
32   }
33 
34   /// Return a printable string representation of this date.
35   string toString() const { return date_.toString; }
36 
37   /// Returns days since Unix epoch.
38   @nogc auto days() const { return (date_ - epoch_).total!"days"; }
39 
40 package:
41   /// Create a Date using the given `mg_date` pointer.
42   @nogc this(const mg_date *ptr) {
43     assert(ptr != null);
44     ptr_ = ptr;
45     date_ = epoch_ + ct.days(mg_date_days(ptr));
46   }
47 
48   /// Return pointer to internal `mg_date`.
49   @nogc auto ptr() inout {
50     return ptr_;
51   }
52 
53 private:
54   const mg_date *ptr_;
55   sd.Date date_;
56   alias date_ this;
57 } // struct Date
58 
59 static private sd.Date epoch_ = sd.Date(1970, 1, 1);
60 
61 unittest {
62   import testutils : connectContainer;
63   import std.algorithm : count;
64   import std.conv : to;
65 
66   auto client = connectContainer();
67   assert(client);
68 
69   auto result = client.execute(`return date('2021-02-12') as a, date('2022-11-12') as b, date('2038-01-20') as c;`);
70   assert(result, client.error);
71   foreach (r; result) {
72     assert(r.length == 3);
73 
74     assert(r[0].type() == Type.Date);
75     const d1 = to!Date(r[0]);
76     assert(d1.days == 18_670, to!string(d1.days));
77     assert(d1.toISOExtString == "2021-02-12");
78     assert(d1.toISOString == "20210212");
79     assert(d1.toString == "2021-Feb-12");
80     const sd.Date D1 = d1;
81     assert(D1.toISOExtString == "2021-02-12");
82     assert(D1.toISOString == "20210212");
83     assert(D1.toString == "2021-Feb-12");
84 
85     assert(r[1].type() == Type.Date);
86     const d2 = to!Date(r[1]);
87     assert(d2.days == 19_308, to!string(d2.days));
88     assert(d2.toISOExtString == "2022-11-12");
89     assert(d2.toISOString == "20221112");
90     assert(d2.toString == "2022-Nov-12");
91     const sd.Date D2 = d2;
92     assert(D2.toISOExtString == "2022-11-12");
93     assert(D2.toISOString == "20221112");
94     assert(D2.toString == "2022-Nov-12");
95 
96     assert(r[2].type() == Type.Date);
97     const d3 = to!Date(r[2]);
98     assert(d3.days == 24_856, to!string(d3.days));
99     assert(d3.toISOExtString == "2038-01-20");
100     assert(d3.toISOString == "20380120");
101     assert(d3.toString == "2038-Jan-20");
102     const sd.Date D3 = d3;
103     assert(D3.toISOExtString == "2038-01-20");
104     assert(D3.toISOString == "20380120");
105     assert(D3.toString == "2038-Jan-20");
106   }
107 }
108 
109 unittest {
110   import memgraph.enums : Type;
111   import std.conv : to;
112 
113   auto dt = mg_date_make(42);
114   assert(dt != null);
115 
116   auto d = Date(dt);
117   assert(d.days == 42);
118 
119   const d1 = d;
120   assert(d1 == d);
121 
122   assert(to!string(d) == "1970-Feb-12", to!string(d));
123 
124   auto d2 = Date(mg_date_copy(d.ptr));
125   assert(d2 == d);
126 
127   const d3 = Date(d2);
128   assert(d3 == d);
129 
130   const d5 = Date(d3);
131   assert(d5 == d3);
132 
133   auto v = Value(mg_value_make_date(dt));
134   assert(to!string(v) == "1970-Feb-12", to!string(v));
135 
136   assert(cast(ulong)d.ptr == d.toHash);
137 }