1 module database.mysql.appender;
2 
3 import std.datetime;
4 import std.traits;
5 import std.typecons;
6 
7 import database.mysql.type;
8 
9 void appendValues(Appender, T)(ref Appender appender, T values) if (isArray!T && !isSomeString!(OriginalType!T))
10 {
11     foreach (size_t i, value; values)
12     {
13         appendValue(appender, value);
14         if (i != values.length - 1)
15             appender.put(',');
16     }
17 }
18 
19 void appendValue(Appender, T)(ref Appender appender, T value) if (is(Unqual!T == typeof(null)))
20 {
21     appender.put("null");
22 }
23 
24 void appendValue(Appender, T)(ref Appender appender, T value) if (isInstanceOf!(Nullable, T) || isInstanceOf!(NullableRef, T))
25 {
26     if (value.isNull)
27     {
28         appendValue(appender, null);
29     }
30     else
31     {
32         appendValue(appender, value.get);
33     }
34 }
35 
36 void appendValue(Appender, T)(ref Appender appender, T value) if (isScalarType!T)
37 {
38     appender.put(cast(ubyte[])to!string(value));
39 }
40 
41 void appendValue(Appender, T)(ref Appender appender, T value) if (is(Unqual!T == SysTime))
42 {
43     value = value.toUTC;
44 
45     auto hour = value.hour;
46     auto minute = value.minute;
47     auto second = value.second;
48     auto usec = value.fracSecs.total!"usecs";
49 
50     formattedWrite(appender, "%04d%02d%02d", value.year, value.month, value.day);
51     if (hour | minute | second | usec)
52     {
53         formattedWrite(appender, "%02d%02d%02d", hour, minute, second);
54         if (usec)
55             formattedWrite(appender, ".%06d", usec);
56     }
57 }
58 
59 void appendValue(Appender, T)(ref Appender appender, T value) if (is(Unqual!T == DateTime))
60 {
61     auto hour = value.hour;
62     auto minute = value.minute;
63     auto second = value.second;
64 
65     if (hour | minute | second)
66     {
67         formattedWrite(appender, "%04d%02d%02d%02d%02d%02d", value.year, value.month, value.day, hour, minute, second);
68     }
69     else
70     {
71         formattedWrite(appender, "%04d%02d%02d", value.year, value.month, value.day);
72     }
73 }
74 
75 void appendValue(Appender, T)(ref Appender appender, T value) if (is(Unqual!T == TimeOfDay))
76 {
77     formattedWrite(appender, "%02d%02d%02d", value.hour, value.minute, value.second);
78 }
79 
80 void appendValue(Appender, T)(ref Appender appender, T value) if (is(Unqual!T == Date))
81 {
82     formattedWrite(appender, "%04d%02d%02d", value.year, value.month, value.day);
83 }
84 
85 void appendValue(Appender, T)(ref Appender appender, T value) if (is(Unqual!T == Duration))
86 {
87     auto parts = value.split();
88     if (parts.days)
89     {
90         appender.put('\'');
91         formattedWrite(appender, "%d ", parts.days);
92     }
93     formattedWrite(appender, "%02d%02d%02d", parts.hours, parts.minutes, parts.seconds);
94     if (parts.usecs)
95         formattedWrite(appender, ".%06d ", parts.usecs);
96     if (parts.days)
97         appender.put('\'');
98 }
99 
100 void appendValue(Appender, T)(ref Appender appender, T value) if (is(Unqual!T == MySQLFragment))
101 {
102     appender.put(cast(char[])value.data);
103 }
104 
105 void appendValue(Appender, T)(ref Appender appender, T value) if (is(Unqual!T == MySQLRawString))
106 {
107     appender.put('\'');
108     appender.put(cast(char[])value.data);
109     appender.put('\'');
110 }
111 
112 void appendValue(Appender, T)(ref Appender appender, T value) if (is(Unqual!T == MySQLBinary))
113 {
114     appendValue(appender, value.data);
115 }
116 
117 void appendValue(Appender, T)(ref Appender appender, T value) if (is(Unqual!T == MySQLValue))
118 {
119     final switch(value.type) with (ColumnTypes)
120     {
121         case MYSQL_TYPE_NULL:
122             appender.put("null");
123             break;
124         case MYSQL_TYPE_TINY:
125             if (value.isSigned)
126             {
127                 appendValue(appender, value.peek!byte);
128             }
129             else
130             {
131                 appendValue(appender, value.peek!ubyte);
132             }
133             break;
134         case MYSQL_TYPE_YEAR:
135         case MYSQL_TYPE_SHORT:
136             if (value.isSigned)
137             {
138                 appendValue(appender, value.peek!short);
139             }
140             else
141             {
142                 appendValue(appender, value.peek!ushort);
143             }
144             break;
145         case MYSQL_TYPE_INT24:
146         case MYSQL_TYPE_LONG:
147             if (value.isSigned)
148             {
149                 appendValue(appender, value.peek!int);
150             }
151             else
152             {
153                 appendValue(appender, value.peek!uint);
154             }
155             break;
156         case MYSQL_TYPE_LONGLONG:
157             if (value.isSigned)
158             {
159                 appendValue(appender, value.peek!long);
160             }
161             else
162             {
163                 appendValue(appender, value.peek!ulong);
164             }
165             break;
166         case MYSQL_TYPE_DOUBLE:
167             appendValue(appender, value.peek!double);
168             break;
169         case MYSQL_TYPE_FLOAT:
170             appendValue(appender, value.peek!float);
171             break;
172         case MYSQL_TYPE_SET:
173         case MYSQL_TYPE_ENUM:
174         case MYSQL_TYPE_VARCHAR:
175         case MYSQL_TYPE_VAR_STRING:
176         case MYSQL_TYPE_STRING:
177         case MYSQL_TYPE_JSON:
178         case MYSQL_TYPE_NEWDECIMAL:
179         case MYSQL_TYPE_DECIMAL:
180             appendValue(appender, value.peek!(char[]));
181             break;
182         case MYSQL_TYPE_BIT:
183         case MYSQL_TYPE_TINY_BLOB:
184         case MYSQL_TYPE_MEDIUM_BLOB:
185         case MYSQL_TYPE_LONG_BLOB:
186         case MYSQL_TYPE_BLOB:
187         case MYSQL_TYPE_GEOMETRY:
188             appendValue(appender, value.peek!(ubyte[]));
189             break;
190         case MYSQL_TYPE_TIME:
191         case MYSQL_TYPE_TIME2:
192             appendValue(appender, value.peek!Duration);
193             break;
194         case MYSQL_TYPE_DATE:
195         case MYSQL_TYPE_NEWDATE:
196         case MYSQL_TYPE_DATETIME:
197         case MYSQL_TYPE_DATETIME2:
198         case MYSQL_TYPE_TIMESTAMP:
199         case MYSQL_TYPE_TIMESTAMP2:
200             appendValue(appender, value.peek!SysTime);
201             break;
202     }
203 }
204 
205 void appendValue(Appender, T)(ref Appender appender, T value) if (isArray!T && (is(Unqual!(typeof(T.init[0])) == ubyte) || is(Unqual!(typeof(T.init[0])) == char)))
206 {
207     appender.put('\'');
208     auto ptr = value.ptr;
209     auto end = value.ptr + value.length;
210     while (ptr != end)
211     {
212         switch(*ptr)
213         {
214             case '\\':
215             case '\'':
216                 appender.put('\\');
217                 goto default;
218             default:
219                 appender.put(*ptr++);
220         }
221     }
222     appender.put('\'');
223 }