1 // Written in D programming language
2 /**
3 *   This module defines high-level wrapper around libpq bindings.
4 *
5 *   The major goals:
6 *   <ul>
7 *       <li>Get more control over library errors (by converting to exceptions)</li>
8 *       <li>Create layer that can be mocked in purpose of unittesting</li>
9 *   </ul>
10 *
11 *   Copyright: © 2014 DSoftOut
12 *   License: Subject to the terms of the MIT license, as written in the included LICENSE file.
13 *   Authors: NCrashed <ncrashed@gmail.com>
14 */
15 module pgator.db.pq.api;
16 
17 import dpq2.answer;
18 public import pgator.db.pq.types.oids;
19 import pgator.db.connection;
20 import pgator.db.pq.types.conv;
21 import vibe.data.bson;
22 import dlogg.log;
23 
24 /**
25 *   Prototype: PGResult
26 */
27 interface IPGresult
28 {
29     synchronized:
30     
31     /**
32     *   Prototype: PQresultStatus
33     */
34     ExecStatusType resultStatus() nothrow const;
35     
36     /**
37     *   Prototype: PQresStatus
38     *   Note: same as resultStatus, but converts 
39     *         the enum to human-readable string.
40     */
41     string resStatus() const;
42     
43     /**
44     *   Prototype: PQresultErrorMessage
45     */
46     string resultErrorMessage() const;
47     
48     /**
49     *   Prototype: PQclear
50     */
51     //void clear() nothrow;
52     
53     /**
54     *   Prototype: PQntuples
55     */
56     size_t ntuples() const nothrow;
57 
58     /**
59     *   Prototype: PQnfields
60     */
61     size_t nfields() const nothrow;
62         
63     /**
64     *   Prototype: PQfname
65     */ 
66     string fname(size_t colNumber) const;
67     
68     /**
69     *   Prototype: PQfformat
70     */
71     bool isBinary(size_t colNumber) const;
72     
73     /**
74     *   Prototype: PQgetvalue
75     */
76     string asString(size_t rowNumber, size_t colNumber) const;
77     
78     /**
79     *   Prototype: PQgetvalue
80     */
81     ubyte[] asBytes(size_t rowNumber, size_t colNumber) const;
82     
83     /**
84     *   Prototype: PQgetisnull
85     */
86     bool getisnull(size_t rowNumber, size_t colNumber) const;
87     
88     /**
89     *   Prototype: PQftype
90     */
91     OidType ftype(size_t colNumber) const;
92     
93     /**
94     *   Creates Bson from result in column echelon order.
95     *   
96     *   Bson consists of named arrays of column values.
97     */
98     Bson asColumnBson(shared IConnection conn) const;
99     
100     /// Getting local logger
101     protected shared(ILogger) logger() nothrow;
102 }
103 
104 /**
105 *   Prototype: PGconn
106 */
107 interface IPGconn
108 {
109     synchronized:
110     
111     /**
112     *   Prototype: PQconnectPoll
113     */
114     PostgresPollingStatusType poll() nothrow;
115     
116     /**
117     *   Prototype: PQstatus
118     */
119     ConnStatusType status() nothrow;
120     
121     /**
122     *   Prototype: PQfinish
123     *   Note: this function should be called even
124     *   there was an error.
125     */
126     void finish() nothrow;
127     
128     /**
129     *   Prototype: PQflush
130     */
131     bool flush() nothrow const;
132     
133     /**
134     *   Prototype: PQresetStart
135     *   Throws: PGReconnectException
136     */
137     void resetStart();
138     
139     /**
140     *   Prototype: PQresetPoll
141     */
142     PostgresPollingStatusType resetPoll() nothrow;
143 
144     /**
145     *   Prototype: PQerrorMessage
146     */
147     string errorMessage() const nothrow @property;
148     
149     /**
150     *   Prototype: PQsendQueryParams
151     *   Note: This is simplified version of the command that
152     *         handles only string params.
153     *   Warning: libpq doesn't support multiple SQL commands in
154     *            the function. See the sendQueryParamsExt as
155     *            an extended version of the function. 
156     *   Throws: PGQueryException
157     */
158     void sendQueryParams(string command, string[] paramValues); 
159     
160     /**
161     *   Prototype: PQsendQuery
162     *   Throws: PGQueryException
163     */
164     void sendQuery(string command);
165     
166     /**
167     *   Like sendQueryParams but uses libpq escaping functions
168     *   and sendQuery. 
169     *   
170     *   The main advantage of the function is ability to handle
171     *   multiple SQL commands in one query.
172     *   Throws: PGQueryException
173     */
174     void sendQueryParamsExt(string command, string[] paramValues);
175      
176     /**
177     *   Prototype: PQgetResult
178     *   Note: Even when PQresultStatus indicates a fatal error, 
179     *         PQgetResult should be called until it returns a null pointer 
180     *         to allow libpq to process the error information completely.
181     *   Note: A null pointer is returned when the command is complete and t
182     *         here will be no more results.
183     */
184     shared(IPGresult) getResult();
185     
186     /**
187     *   Prototype: PQconsumeInput
188     *   Throws: PGQueryException
189     */
190     void consumeInput();
191     
192     /**
193     *   Prototype: PQisBusy
194     */
195     bool isBusy() nothrow;
196     
197     /**
198     *   Prototype: PQescapeLiteral
199     *   Throws: PGEscapeException
200     */
201     string escapeLiteral(string msg);
202     
203     /**
204     *   Prototype: PQparameterStatus
205     *   Throws: PGParamNotExistException
206     */
207     string parameterStatus(string param);
208     
209     /**
210     *   Prototype: PQsetNoticeProcessor
211     */
212     PQnoticeProcessor setNoticeProcessor(PQnoticeProcessor proc, void* arg) nothrow;
213     
214     /// Getting local logger
215     protected shared(ILogger) logger() nothrow;
216 
217     string server() nothrow;
218 }
219 
220 /**
221 *   OOP styled libpq wrapper to automatically handle library loading/unloading and
222 *   to provide mockable layer for unittests. 
223 */
224 shared interface IPostgreSQL
225 {
226     /**
227     *   Prototype: PQconnectStart
228     *   Throws: PGMemoryLackException
229     */
230     shared(IPGconn) startConnect(string conninfo);
231 }