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