1 module database.postgresql.appender; 2 3 import std.conv; 4 import std.datetime; 5 import std.format; 6 import std.traits; 7 import std.typecons; 8 9 import database.postgresql.protocol; 10 import database.postgresql.type; 11 12 void appendValues(Appender, T)(ref Appender appender, T values) if (isArray!T && !isSomeString!(OriginalType!T)) 13 { 14 foreach (size_t i, value; values) 15 { 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 { 24 appender.put("null"); 25 } 26 27 void appendValue(Appender, T)(ref Appender appender, T value) if (isInstanceOf!(Nullable, T) || isInstanceOf!(NullableRef, T)) 28 { 29 if (value.isNull) 30 { 31 appendValue(appender, null); 32 } 33 else 34 { 35 appendValue(appender, value.get); 36 } 37 } 38 39 void appendValue(Appender, T)(ref Appender appender, T value) if (isScalarType!T) 40 { 41 static if (isBoolean!T) 42 { 43 appender.put(value ? "'t'" : "'f'"); 44 } 45 else 46 { 47 appender.put(cast(ubyte[])to!string(value)); 48 } 49 } 50 51 void appendValue(Appender, T)(ref Appender appender, T value) if (is(Unqual!T == SysTime)) 52 { 53 value = value.toUTC; 54 55 auto hour = value.hour; 56 auto minute = value.minute; 57 auto second = value.second; 58 auto usec = value.fracSecs.total!"usecs"; 59 60 formattedWrite(appender, "'%04d%02d%02d", value.year, value.month, value.day); 61 if (hour | minute | second | usec) 62 { 63 formattedWrite(appender, " %02d%02d%02d", hour, minute, second); 64 if (usec) 65 formattedWrite(appender, ".%06d", usec); 66 } 67 appender.put('\''); 68 } 69 70 void appendValue(Appender, T)(ref Appender appender, T value) if (is(Unqual!T == DateTime)) 71 { 72 auto hour = value.hour; 73 auto minute = value.minute; 74 auto second = value.second; 75 76 if (hour | minute | second) 77 { 78 formattedWrite(appender, "'%04d%02d%02d%02d%02d%02d'", value.year, value.month, value.day, hour, minute, second); 79 } 80 else 81 { 82 formattedWrite(appender, "'%04d%02d%02d'", value.year, value.month, value.day); 83 } 84 } 85 86 void appendValue(Appender, T)(ref Appender appender, T value) if (is(Unqual!T == TimeOfDay)) 87 { 88 formattedWrite(appender, "'%02d%02d%02d'", value.hour, value.minute, value.second); 89 } 90 91 void appendValue(Appender, T)(ref Appender appender, T value) if (is(Unqual!T == Date)) 92 { 93 formattedWrite(appender, "'%04d%02d%02d'", value.year, value.month, value.day); 94 } 95 96 void appendValue(Appender, T)(ref Appender appender, T value) if (is(Unqual!T == PgSQLFragment)) 97 { 98 appender.put(cast(char[])value.data); 99 } 100 101 void appendValue(Appender, T)(ref Appender appender, T value) if (is(Unqual!T == PgSQLRawString)) 102 { 103 appender.put('\''); 104 appender.put(cast(char[])value.data); 105 appender.put('\''); 106 } 107 108 void appendValue(Appender, T)(ref Appender appender, T value) if (is(Unqual!T == PgSQLBinary)) 109 { 110 appendValue(appender, value.data); 111 } 112 113 void appendValue(Appender, T)(ref Appender appender, T value) if (is(Unqual!T == PgSQLValue)) 114 { 115 final switch(value.type) with (PgColumnTypes) 116 { 117 case UNKNOWN: 118 case NULL: 119 appender.put("null"); 120 break; 121 case CHAR: 122 appendValue(appender, value.peek!char); 123 break; 124 case BOOL: 125 appendValue(appender, value.peek!bool); 126 break; 127 case INT2: 128 appendValue(appender, value.peek!short); 129 break; 130 case INT4: 131 appendValue(appender, value.peek!int); 132 break; 133 case INT8: 134 appendValue(appender, value.peek!long); 135 break; 136 case REAL: 137 appendValue(appender, value.peek!float); 138 break; 139 case DOUBLE: 140 appendValue(appender, value.peek!double); 141 break; 142 case POINT: 143 case LSEG: 144 case PATH: 145 case BOX: 146 case POLYGON: 147 case LINE: 148 case TINTERVAL: 149 case INTERVAL: 150 case CIRCLE: 151 case BYTEA: 152 case JSONB: 153 appendValue(appender, value.peek!(ubyte[])); 154 break; 155 case NUMERIC: 156 case MONEY: 157 case BIT: 158 case VARBIT: 159 case INET: 160 case CIDR: 161 case MACADDR: 162 case MACADDR8: 163 case UUID: 164 case JSON: 165 case XML: 166 case TEXT: 167 case NAME: 168 case VARCHAR: 169 case CHARA: 170 appendValue(appender, value.peek!(char[])); 171 break; 172 case DATE: 173 appendValue(appender, value.peek!Date); 174 break; 175 case TIMETZ: 176 case TIME: 177 appendValue(appender, value.peek!TimeOfDay); 178 break; 179 case TIMESTAMP: 180 appendValue(appender, value.peek!DateTime); 181 break; 182 case TIMESTAMPTZ: 183 appendValue(appender, value.peek!SysTime); 184 break; 185 } 186 } 187 188 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))) 189 { 190 appender.put('\''); 191 auto ptr = value.ptr; 192 auto end = value.ptr + value.length; 193 while (ptr != end) 194 { 195 switch(*ptr) 196 { 197 case '\\': 198 case '\'': 199 appender.put('\\'); 200 goto default; 201 default: 202 appender.put(*ptr++); 203 } 204 } 205 appender.put('\''); 206 }