1 module dpq.query;
2 
3 import dpq.connection;
4 import dpq.value;
5 import dpq.exception;
6 import dpq.result;
7 
8 version(unittest)
9 {
10 	import std.stdio;
11 	private Connection c;
12 }
13 
14 struct Query
15 {
16 	private string _command;
17 	private Value[] _params;
18 	private Connection* _connection;
19 
20 	this(string command, Value[] params = [])
21 	{
22 		if (_dpqLastConnection == null)
23 			throw new DPQException("Query: No established connection was found and none was provided.");
24 
25 		_connection = _dpqLastConnection;
26 		_command = command;
27 		_params = params;
28 	}
29 
30 	this(ref Connection conn, string command = "", Value[] params = [])
31 	{
32 		_connection = &conn;
33 		_command = command;
34 		_params = params;
35 	}
36 
37 
38 	unittest
39 	{
40 		writeln(" * Query");
41 
42 		c = Connection("host=127.0.0.1 dbname=test user=test");
43 
44 		writeln("\t * this()");
45 		Query q;
46 		assert(q._connection == null);
47 
48 		writeln("\t * this(command, params[])");
49 		string cmd = "some command";
50 		q = Query(cmd);
51 		assert(q._connection != null, `not null 2`);
52 		assert(q._command == cmd, `cmd`);
53 		assert(q._params == [], `empty arr`);
54 
55 		Connection c2 = Connection("host=127.0.0.1 dbname=test user=test");
56 		writeln("\t * this(Connection, command, params[])");
57 		q = Query(c2);
58 		assert(q._connection == &c2);
59 
60 		q = Query(cmd);
61 		assert(q._connection == &c2);
62 	}
63 
64 	@property void connection(ref Connection conn)
65 	{
66 		_connection = &conn;
67 	}
68 
69 	@property string command()
70 	{
71 		return _command;
72 	}
73 	
74 	@property void command(string c)
75 	{
76 		_command = c;
77 	}
78 
79 	void addParam(T)(T val)
80 	{
81 		_params ~= Value(val);
82 	}
83 
84 	unittest
85 	{
86 		Query q;
87 		assert(q._params.length == 0);
88 
89 		q.addParam(1);
90 
91 		assert(q._params.length == 1);
92 		assert(q._params[0] == Value(1));
93 	}
94 
95 	ref Query opBinary(string op, T)(T val)
96 			if (op == "<<")
97 	{
98 		addParam(val);
99 		return this;
100 	}
101 
102 	void opAssign(string str)
103 	{
104 		command = str;
105 	}
106 
107 	@property Result run()
108 	{
109 		import std.datetime;
110 
111 		StopWatch sw;
112 		sw.start();
113 
114 		Result r = _connection.execParams(_command, _params);
115 		sw.stop();
116 
117 		r.time = sw.peek();
118 		return r;
119 	}
120 
121 	Result run(T...)(T params)
122 	{
123 		foreach (p; params)
124 			addParam(p);
125 
126 		return run();
127 	}
128 
129 	bool runAsync(T...)(T params)
130 	{
131 		foreach (p; params)
132 			addParam(p);
133 
134 		return runAsync();
135 	}
136 
137 	bool runAsync()
138 	{
139 		_connection.sendParams(_command, _params);
140 		return true; // FIXME: must return the actual result from PQsendQueryParams
141 	}
142 
143 	unittest
144 	{
145 		writeln("\t * run");
146 
147 		auto c = Connection("host=127.0.0.1 dbname=test user=test");
148 		
149 		auto q = Query("SELECT 1::INT");
150 
151 		auto r = q.run();
152 		assert(r.rows == 1);
153 		assert(r.columns == 1);
154 		assert(r[0][0].as!int == 1);
155 
156 		writeln("\t\t * async");
157 		q.runAsync();
158 
159 		r = c.lastResult();
160 		assert(r.rows == 1);
161 		assert(r.columns == 1);
162 		assert(r[0][0].as!int == 1);
163 
164 		writeln("\t * run(params...)");
165 
166 		q = "SELECT $1";
167 		q.run(1);
168 		assert(r.rows == 1);
169 		assert(r.columns == 1);
170 		assert(r[0][0].as!int == 1);
171 
172 		writeln("\t\t * async");
173 
174 		q.runAsync(1);
175 		r = c.lastResult();
176 		assert(r.rows == 1);
177 		assert(r.columns == 1);
178 		assert(r[0][0].as!int == 1);
179 	}
180 }