1 module pgsql.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 pgsql.protocol;
11 import pgsql.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 	static if (isBoolean!T) {
36 		appender.put(value ? "'t'" : "'f'");
37 	} else {
38 		appender.put(cast(ubyte[])to!string(value));
39 	}
40 }
41 
42 void appendValue(Appender, T)(ref Appender appender, T value) if (is(Unqual!T == SysTime)) {
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 		formattedWrite(appender, " %02d%02d%02d", hour, minute, second);
53 		if (usec)
54 			formattedWrite(appender, ".%06d", usec);
55 	}
56 	appender.put('\'');
57 }
58 
59 void appendValue(Appender, T)(ref Appender appender, T value) if (is(Unqual!T == DateTime)) {
60 	auto hour = value.hour;
61 	auto minute = value.minute;
62 	auto second = value.second;
63 
64 	if (hour | minute | second) {
65 		formattedWrite(appender, "'%04d%02d%02d%02d%02d%02d'", value.year, value.month, value.day, hour, minute, second);
66 	} else {
67 		formattedWrite(appender, "'%04d%02d%02d'", value.year, value.month, value.day);
68 	}
69 }
70 
71 void appendValue(Appender, T)(ref Appender appender, T value) if (is(Unqual!T == TimeOfDay)) {
72 	formattedWrite(appender, "'%02d%02d%02d'", value.hour, value.minute, value.second);
73 }
74 
75 void appendValue(Appender, T)(ref Appender appender, T value) if (is(Unqual!T == Date)) {
76 	formattedWrite(appender, "'%04d%02d%02d'", value.year, value.month, value.day);
77 }
78 
79 void appendValue(Appender, T)(ref Appender appender, T value) if (is(Unqual!T == PgSQLFragment)) {
80 	appender.put(cast(char[])value.data);
81 }
82 
83 void appendValue(Appender, T)(ref Appender appender, T value) if (is(Unqual!T == PgSQLRawString)) {
84 	appender.put('\'');
85 	appender.put(cast(char[])value.data);
86 	appender.put('\'');
87 }
88 
89 void appendValue(Appender, T)(ref Appender appender, T value) if (is(Unqual!T == PgSQLBinary)) {
90 	appendValue(appender, value.data);
91 }
92 
93 void appendValue(Appender, T)(ref Appender appender, T value) if (is(Unqual!T == PgSQLValue)) {
94 	final switch(value.type) with (PgColumnTypes) {
95 	case UNKNOWN:
96 	case NULL:
97 		appender.put("null");
98 		break;
99 	case CHAR:
100 		appendValue(appender, value.peek!char);
101 		break;
102 	case BOOL:
103 		appendValue(appender, value.peek!bool);
104 		break;
105 	case INT2:
106 		appendValue(appender, value.peek!short);
107 		break;
108 	case INT4:
109 		appendValue(appender, value.peek!int);
110 		break;
111 	case INT8:
112 		appendValue(appender, value.peek!long);
113 		break;
114 	case REAL:
115 		appendValue(appender, value.peek!float);
116 		break;
117 	case DOUBLE:
118 		appendValue(appender, value.peek!double);
119 		break;
120 	case POINT:
121 	case LSEG:
122 	case PATH:
123 	case BOX:
124 	case POLYGON:
125 	case LINE:
126 	case TINTERVAL:
127 	case INTERVAL:
128 	case CIRCLE:
129 	case BYTEA:
130 	case JSONB:
131 		appendValue(appender, value.peek!(ubyte[]));
132 		break;
133 	case NUMERIC:
134 	case MONEY:
135 	case BIT:
136 	case VARBIT:
137 	case INET:
138 	case CIDR:
139 	case MACADDR:
140 	case MACADDR8:
141 	case UUID:
142 	case JSON:
143 	case XML:
144 	case TEXT:
145 	case NAME:
146 	case VARCHAR:
147 	case CHARA:
148 		appendValue(appender, value.peek!(char[]));
149 		break;
150 	case DATE:
151 		appendValue(appender, value.peek!Date);
152 		break;
153 	case TIMETZ:
154 	case TIME:
155 		appendValue(appender, value.peek!TimeOfDay);
156 		break;
157 	case TIMESTAMP:
158 		appendValue(appender, value.peek!DateTime);
159 		break;
160 	case TIMESTAMPTZ:
161 		appendValue(appender, value.peek!SysTime);
162 		break;
163 	}
164 }
165 
166 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))) {
167 	appender.put('\'');
168 	auto ptr = value.ptr;
169 	auto end = value.ptr + value.length;
170 	while (ptr != end) {
171 		switch(*ptr) {
172 		case '\\':
173 		case '\'':
174 			appender.put('\\');
175 			goto default;
176 		default:
177 			appender.put(*ptr++);
178 		}
179 	}
180 	appender.put('\'');
181 }