forked from brianc/node-libpq
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
354 lines (310 loc) · 10.4 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
var PQ = module.exports = require('bindings')('addon.node').PQ;
//print out the include dir
//if you want to include this in a binding.gyp file
if(!module.parent) {
var path = require('path');
console.log(path.normalize(__dirname + '/src'));
}
var EventEmitter = require('events').EventEmitter;
var assert = require('assert');
for(var key in EventEmitter.prototype) {
PQ.prototype[key] = EventEmitter.prototype[key];
}
//SYNC connects to the server
//throws an exception in the event of a connection error
PQ.prototype.connectSync = function(paramString) {
this.connected = true;
if(!paramString) {
paramString = '';
}
var connected = this.$connectSync(paramString);
if(!connected) {
var err = new Error(this.errorMessage());
this.finish();
throw err;
}
};
//connects async using a background thread
//calls the callback with an error if there was one
PQ.prototype.connect = function(paramString, cb) {
this.connected = true;
if(typeof paramString == 'function') {
cb = paramString;
paramString = '';
}
if(!paramString) {
paramString = '';
}
assert(cb, 'Must provide a connection callback');
if(process.domain) {
cb = process.domain.bind(cb);
}
this.$connect(paramString, cb);
};
PQ.prototype.errorMessage = function() {
return this.$getLastErrorMessage();
};
//returns an int for the fd of the socket
PQ.prototype.socket = function() {
return this.$socket();
};
//finishes the connection & closes it
PQ.prototype.finish = function() {
this.connected = false;
this.$finish();
};
////SYNC executes a plain text query
//immediately stores the results within the PQ object for consumption with
//ntuples, getvalue, etc...
//returns false if there was an error
//consume additional error details via PQ#errorMessage & friends
PQ.prototype.exec = function(commandText) {
if(!commandText) {
commandText = '';
}
this.$exec(commandText);
};
//SYNC executes a query with parameters
//immediately stores the results within the PQ object for consumption with
//ntuples, getvalue, etc...
//returns false if there was an error
//consume additional error details via PQ#errorMessage & friends
PQ.prototype.execParams = function(commandText, parameters) {
if(!commandText) {
commandText = '';
}
if(!parameters) {
parameters = [];
}
this.$execParams(commandText, parameters);
};
//SYNC prepares a named query and stores the result
//immediately stores the results within the PQ object for consumption with
//ntuples, getvalue, etc...
//returns false if there was an error
//consume additional error details via PQ#errorMessage & friends
PQ.prototype.prepare = function(statementName, commandText, nParams) {
assert.equal(arguments.length, 3, 'Must supply 3 arguments');
if(!statementName) {
statementName = '';
}
if(!commandText) {
commandText = '';
}
nParams = Number(nParams) || 0;
this.$prepare(statementName, commandText, nParams);
};
//SYNC executes a named, prepared query and stores the result
//immediately stores the results within the PQ object for consumption with
//ntuples, getvalue, etc...
//returns false if there was an error
//consume additional error details via PQ#errorMessage & friends
PQ.prototype.execPrepared = function(statementName, parameters) {
if(!statementName) {
statementName = '';
}
if(!parameters) {
parameters = [];
}
this.$execPrepared(statementName, parameters);
};
//send a command to begin executing a query in async mode
//returns true if sent, or false if there was a send failure
PQ.prototype.sendQuery = function(commandText) {
if(!commandText) {
commandText = '';
}
return this.$sendQuery(commandText);
};
//send a command to begin executing a query with parameters in async mode
//returns true if sent, or false if there was a send failure
PQ.prototype.sendQueryParams = function(commandText, parameters) {
if(!commandText) {
commandText = '';
}
if(!parameters) {
parameters = [];
}
return this.$sendQueryParams(commandText, parameters);
};
//send a command to prepare a named query in async mode
//returns true if sent, or false if there was a send failure
PQ.prototype.sendPrepare = function(statementName, commandText, nParams) {
assert.equal(arguments.length, 3, 'Must supply 3 arguments');
if(!statementName) {
statementName = '';
}
if(!commandText) {
commandText = '';
}
nParams = Number(nParams) || 0;
return this.$sendPrepare(statementName, commandText, nParams);
};
//send a command to execute a named query in async mode
//returns true if sent, or false if there was a send failure
PQ.prototype.sendQueryPrepared = function(statementName, parameters) {
if(!statementName) {
statementName = '';
}
if(!parameters) {
parameters = [];
}
return this.$sendQueryPrepared(statementName, parameters);
};
//'pops' a result out of the buffered
//response data read during async command execution
//and stores it on the c/c++ object so you can consume
//the data from it. returns true if there was a pending result
//or false if there was no pending result. if there was no pending result
//the last found result is not overwritten so you can call getResult as many
//times as you want, and you'll always have the last available result for consumption
PQ.prototype.getResult = function() {
return this.$getResult();
};
//returns a text of the enum associated with the result
//usually just PGRES_COMMAND_OK or PGRES_FATAL_ERROR
PQ.prototype.resultStatus = function() {
return this.$resultStatus();
};
PQ.prototype.resultErrorMessage = function() {
return this.$resultErrorMessage();
};
PQ.prototype.resultErrorFields = function() {
return this.$resultErrorFields();
};
//free the memory associated with a result
//this is somewhat handled for you within the c/c++ code
//by never allowing the code to 'leak' a result. still,
//if you absolutely want to free it yourself, you can use this.
PQ.prototype.clear = function() {
this.$clear();
};
//returns the number of tuples (rows) in the result set
PQ.prototype.ntuples = function() {
return this.$ntuples();
};
//returns the number of fields (columns) in the result set
PQ.prototype.nfields = function() {
return this.$nfields();
};
//returns the name of the field (column) at the given offset
PQ.prototype.fname = function(offset) {
return this.$fname(offset);
};
//returns the Oid of the type for the given field
PQ.prototype.ftype = function(offset) {
return this.$ftype(offset);
};
//returns a text value at the given row/col
//if the value is null this still returns empty string
//so you need to use PQ#getisnull to determine
PQ.prototype.getvalue = function(row, col) {
return this.$getvalue(row, col);
};
//returns true/false if the value is null
PQ.prototype.getisnull = function(row, col) {
return this.$getisnull(row, col);
};
//returns the status of the command
PQ.prototype.cmdStatus = function() {
return this.$cmdStatus();
};
//returns the tuples in the command
PQ.prototype.cmdTuples = function() {
return this.$cmdTuples();
};
//starts the 'read ready' libuv socket listener.
//Once the socket becomes readable, the PQ instance starts
//emitting 'readable' events. Similar to how node's readable-stream
//works except to clear the SELECT() notification you need to call
//PQ#consumeInput instead of letting node pull the data off the socket
//http://www.postgresql.org/docs/9.1/static/libpq-async.html
PQ.prototype.startReader = function() {
assert(this.connected, 'Must be connected to start reader');
this.$startRead();
};
//suspends the libuv socket 'read ready' listener
PQ.prototype.stopReader = function() {
this.$stopRead();
};
PQ.prototype.writable = function(cb) {
assert(this.connected, 'Must be connected to start writer');
this.$startWrite();
return this.once('writable', cb);
};
//returns boolean - false indicates an error condition
//e.g. a failure to consume input
PQ.prototype.consumeInput = function() {
return this.$consumeInput();
};
//returns true if PQ#getResult would cause
//the process to block waiting on results
//false indicates PQ#getResult can be called
//with an assurance of not blocking
PQ.prototype.isBusy = function() {
return this.$isBusy();
};
//toggles the socket blocking on outgoing writes
PQ.prototype.setNonBlocking = function(truthy) {
return this.$setNonBlocking(truthy ? 1 : 0);
};
//returns true if the connection is non-blocking on writes, otherwise false
//note: connection is always non-blocking on reads if using the send* methods
PQ.prototype.isNonBlocking = function() {
return this.$isNonBlocking();
};
//returns 1 if socket is not write-ready
//returns 0 if all data flushed to socket
//returns -1 if there is an error
PQ.prototype.flush = function() {
return this.$flush();
};
//escapes a literal and returns the escaped string
//I'm not 100% sure this doesn't do any I/O...need to check that
PQ.prototype.escapeLiteral = function(input) {
if(!input) return input;
return this.$escapeLiteral(input);
};
PQ.prototype.escapeIdentifier = function(input) {
if(!input) return input;
return this.$escapeIdentifier(input);
};
//Checks for any notifications which may have arrivied
//and returns them as a javascript object: {relname: 'string', extra: 'string', be_pid: int}
//if there are no pending notifications this returns undefined
PQ.prototype.notifies = function() {
return this.$notifies();
};
//Sends a buffer of binary data to the server
//returns 1 if the command was sent successfully
//returns 0 if the command would block (use PQ#writable here if so)
//returns -1 if there was an error
PQ.prototype.putCopyData = function(buffer) {
assert(buffer instanceof Buffer);
return this.$putCopyData(buffer);
};
//Sends a command to 'finish' the copy
//if an error message is passed, it will be sent to the
//backend and signal a request to cancel the copy in
//returns 1 if sent succesfully
//returns 0 if the command would block
//returns -1 if there was an error
PQ.prototype.putCopyEnd = function(errorMessage) {
if(errorMessage) {
return this.$putCopyEnd(errorMessage);
}
return this.$putCopyEnd();
};
//Gets a buffer of data from a copy out command
//if async is passed as true it will not block waiting
//for the result, otherwise this will BLOCK for a result.
//returns a buffer if successful
//returns 0 if copy is still in process (async only)
//returns -1 if the copy is done
//returns -2 if there was an error
PQ.prototype.getCopyData = function(async) {
return this.$getCopyData(!!async);
};
PQ.prototype.cancel = function() {
return this.$cancel();
};