1 /++
2 Conversion utilities that help to work with Mir Series and ndslice.
3 
4 To use this module `mir-algorithm` package should be included into users `dub.json` file.
5 
6 Public_imports:
7     mir.timeserires
8 
9 Authors: Ilya Yaroshenko
10 Copyright: Kaleidic Associates Advisory Limited
11 License: BSD 3-clause
12 +/
13 module influxdb.mir;
14 
15 version(Have_mir_algorithm):
16 
17 static if (__VERSION__ >= 2073)
18 {
19 ////////////////////////////////////
20 import mir.series;
21 import influxdb.api;
22 import std.datetime: DateTime;
23 
24 /++
25 Converts MeasurementSeries.Rows to Mir Series.
26 
27 Params:
28     T = Time type. Default time type is DateTime. Supported types are SysTime, DateTime, and Date.
29     D = Data type. Default data type is double.
30     rows = MeasurementSeries rows
31     columns = List of columns (optional). The "time" colummn is ignored.
32 Returns:
33     2D Mir $(LINK2 https://docs.algorithm.dlang.io/latest/mir_series.html, Series).
34 +/
35 Series!(T*, D*, 2)
36     toMirSeries(T = DateTime, D = double)(
37         MeasurementSeries.Rows rows,
38         const(string)[] columns = null)
39 {
40     // if columns are not set use all columns
41     if (columns is null)
42     {
43         columns = rows.columns;
44     }
45     // always exclude "time" column
46     foreach (i, column; columns)
47     {
48         if (column == "time")
49         {
50             columns = columns[0 .. i] ~ columns[i + 1 .. $];
51             break;
52         }
53     }
54     import mir.ndslice.allocation: slice, uninitSlice;
55     import mir.ndslice.topology: map, as;
56     import mir.array.allocation: array;
57     import std.conv: to;
58     auto time = rows["time"].array.map!influxSysTime.as!T.slice;
59     auto data = uninitSlice!D(time.length, columns.length);
60     foreach (i, column; columns)
61     {
62         auto from = rows[column];
63         foreach (ref elem; data[0 .. $, i])
64         {
65             elem = from.front.to!D;
66             from.popFront;
67         }
68         assert(from.empty);
69     }
70     return time.series(data);
71 }
72 
73 ///
74 @("toMirSeries")
75 unittest
76 {
77     import mir.series;
78     import std.datetime: DateTime;
79 
80     auto influxSeries = MeasurementSeries("coolness",
81         ["time", "foo", "bar"],
82         [
83             ["2015-06-11T20:46:02Z", "1.0", "2.0"],
84             ["2013-02-09T12:34:56Z", "3.0", "4.0"],
85         ]);
86 
87     auto series = influxSeries.rows.toMirSeries;
88 
89     // sort data if required
90     {
91         import mir.algorithm.iteration: all;
92         import mir.ndslice.allocation: uninitSlice;
93         import mir.ndslice.topology: pairwise;
94 
95         if (!series.time.pairwise!"a <= b".all)
96         {
97             series.sort(
98                 uninitSlice!size_t(series.length), // index buffer
99                 uninitSlice!double(series.length)); // data buffer
100         }
101     }
102 
103     assert(series.time == [
104         DateTime(2013,  2,  9, 12, 34, 56),
105         DateTime(2015,  6, 11, 20, 46,  2)]);
106 
107     assert(series.data == [
108         [3.0, 4.0],
109         [1.0, 2.0]]);
110 }
111 ////////////////////////////////////
112 }
113 else
114     pragma(msg, "Warning: influxdb.mir requires DMD Front End >= 2073");