1 module dpq.value;
2 
3 import dpq.result;
4 import dpq.exception;
5 import dpq.meta;
6 import dpq.attributes;
7 import dpq.connection;
8 import dpq.serialisation;
9 
10 //import derelict.pq.pq;
11 import libpq.libpq;
12 
13 import std.algorithm : map;
14 import std.array;
15 import std.conv : to;
16 import std.typecons : Nullable, TypedefType;
17 import std.bitmanip;
18 import std.traits;
19 import std.datetime : SysTime, DateTime;
20 
21 version(unittest) import std.stdio;
22 
23 
24 package enum Type : Oid
25 {
26 	INFER = 0,
27 	BOOL = 16,
28 	BYTEA = 17,
29 	CHAR = 18,
30 	NAME = 19,
31 	INT8 = 20,
32 	INT2 = 21,
33 	INT2VECTOR = 22,
34 	INT4 = 23,
35 	REGPROC = 24,
36 	TEXT = 25,
37 	OID = 26,
38 	TID = 27,
39 	XID = 28,
40 	CID = 29,
41 	OIDVECTOR = 30,
42 	JSON = 114,
43 	XML = 142,
44 	PGNODETREE = 194,
45 	POINT = 600,
46 	LSEG = 601,
47 	PATH = 602,
48 	BOX = 603,
49 	POLYGON = 604,
50 	LINE = 628,
51 	FLOAT4 = 700,
52 	FLOAT8 = 701,
53 	ABSTIME = 702,
54 	RELTIME = 703,
55 	TINTERVAL = 704,
56 	UNKNOWN = 705,
57 	CIRCLE = 718,
58 	CASH = 790,
59 	MACADDR = 829,
60 	INET = 869,
61 	CIDR = 650,
62 	INT2ARRAY = 1005,
63 	INT4ARRAY = 1007,
64 	TEXTARRAY = 1009,
65 	INT8ARRAY = 1016,
66 	OIDARRAY = 1028,
67 	FLOAT4ARRAY = 1021,
68 	ACLITEM = 1033,
69 	CSTRINGARRAY = 1263,
70 	BPCHAR = 1042,
71 	VARCHAR = 1043,
72 	DATE = 1082,
73 	TIME = 1083,
74 	TIMESTAMP = 1114,
75 	TIMESTAMPTZ = 1184,
76 	INTERVAL = 1186,
77 	TIMETZ = 1266,
78 	BIT = 1560,
79 	VARBIT = 1562,
80 	NUMERIC = 1700,
81 	REFCURSOR = 1790,
82 	REGPROCEDURE = 2202,
83 	REGOPER = 2203,
84 	REGOPERATOR = 2204,
85 	REGCLASS = 2205,
86 	REGTYPE = 2206,
87 	REGTYPEARRAY = 2211,
88 	UUID = 2950,
89 	LSN = 3220,
90 	TSVECTOR = 3614,
91 	GTSVECTOR = 3642,
92 	TSQUERY = 3615,
93 	REGCONFIG = 3734,
94 	REGDICTIONARY = 3769,
95 	JSONB = 3802,
96 	INT4RANGE = 3904,
97 	RECORD = 2249,
98 	RECORDARRAY = 2287,
99 	CSTRING = 2275,
100 	ANY = 2276,
101 	ANYARRAY = 2277,
102 	VOID = 2278,
103 	TRIGGER = 2279,
104 	EVTTRIGGER = 3838,
105 	LANGUAGE_HANDLER = 2280,
106 	INTERNAL = 2281,
107 	OPAQUE = 2282,
108 	ANYELEMENT = 2283,
109 	ANYNONARRAY = 2776,
110 	ANYENUM = 3500,
111 	FDW_HANDLER = 3115,
112 	ANYRANGE = 3831,
113 }
114 
115 package Oid[string] customTypes;
116 
117 struct Value
118 {
119 	private
120 	{
121 		ubyte[] _valueBytes;
122 		int _size;
123 		Type _type;
124 		bool _isNull;
125 	}
126 
127 	this(typeof(null) n)
128 	{
129 		_isNull = true;
130 	}
131 
132 	this(T)(T val)
133 	{
134 		opAssign(val);
135 	}
136 
137 	this(T)(T* val, int len, Type type = Type.INFER)
138 	{
139 		_size = len;
140 		_type = type;
141 
142 		_valueBytes = val[0 .. len].dup;
143 	}
144 
145 	void opAssign(T)(T val)
146 			if (isArray!T)
147 	{
148 		_size = (ForeachType!T.sizeof * val.length).to!int;
149 
150 		static if (is(T == ubyte[]))
151 			_valueBytes = val;
152 		else
153 		{
154 			_valueBytes = toBytes(val);
155 			_size = _valueBytes.length.to!int;
156 		}
157 
158 		_type = typeOid!T;
159 	}
160 
161 	void opAssign(T)(T val)
162 			if(!isArray!T)
163 	{
164 		if (isAnyNull(val))
165 		{
166 			_size = 0;
167 			_valueBytes = null;
168 			_isNull = true;
169 
170 			return;
171 		}
172 
173 		_valueBytes = toBytes(val);
174 		_size = _valueBytes.length.to!int;
175 		_type = typeOid!T;
176 	}
177 
178 	void opAssign(string val)
179 	{
180 		import std..string;
181 
182 		_valueBytes = val.representation.dup;
183 		_size = _valueBytes.length.to!int;
184 		_type = Type.TEXT;
185 	}
186 
187 	void opAssign(SysTime val)
188 	{
189 		_type = typeOid!SysTime;
190 		_size = typeof(val.stdTime).sizeof;
191 
192 		_valueBytes = toBytes(val);
193 	}
194 	
195 	void opAssign(Value val)
196 	{
197 		_valueBytes = val._valueBytes;
198 		_size = val._size;
199 		_type = val._type;
200 	}
201 
202 	@property int size()
203 	{
204 		return _size;
205 	}
206 
207 	@property Oid type()
208 	{
209 		return _type;
210 	}
211 	
212 	@property const(ubyte)* valuePointer()
213 	{
214 		return _valueBytes.ptr;
215 	}
216 
217 	T as(T)()
218 		if (isInstanceOf!(Nullable, T))
219 	{
220 		alias RT = ReturnType!(T.get);
221 		return as!(Unqual!RT);
222 	}
223 
224 	Nullable!T as(T)()
225 		if (!isInstanceOf!(Nullable, T))
226 	{
227 		alias RT = Unqual!T;
228 
229 		if (_isNull)
230 			return Nullable!RT.init;
231 
232 		ubyte[] data = _valueBytes[0 .. _size];
233 		return fromBytes!RT(data, _size);
234 	}
235 
236 	unittest
237 	{
238 		import std.typecons : Typedef;
239 
240 		writeln("\t * as");
241 
242 		Value v = "123";
243 		assert(v.as!string == "123");
244 
245 		v = 123;
246 		assert(v.as!int == 123);
247 
248 		v = [[1, 2], [3, 4]];
249 		assert(v.as!(int[][]) == [[1, 2], [3, 4]]);
250 
251 		int[2] arr = [1, 2];
252 		v = arr;
253 
254 		assert(v.as!(int[2]) == [1, 2]);
255 
256 
257 		alias MyInt = Typedef!int;
258 		MyInt x = 2;
259 		v = Value(x);
260 		assert(v.as!MyInt == x, v.as!(MyInt).to!string ~ " and " ~ x.to!string ~ " are not equal");
261 	}
262 }
263 
264 
265 Oid[] paramTypes(Value[] values)
266 {
267 	return array(values.map!(v => v.type));
268 }
269 
270 int[] paramLengths(Value[] values)
271 {
272 	return array(values.map!(v => v.size));
273 }
274 
275 int[] paramFormats(Value[] values)
276 {
277 	return array(values.map!(v => 1));
278 }
279 
280 const(ubyte)*[] paramValues(Value[] values)
281 {
282 	return array(values.map!(v => v.valuePointer));
283 }