Skip to content

Commit d2e3dfb

Browse files
committed
split query out from client file and did minor refactorings
1 parent 7ce1dde commit d2e3dfb

File tree

2 files changed

+175
-179
lines changed

2 files changed

+175
-179
lines changed

lib/client.js

Lines changed: 3 additions & 179 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ var sys = require('sys');
22
var net = require('net');
33
var crypto = require('crypto');
44
var EventEmitter = require('events').EventEmitter;
5-
5+
var Query = require(__dirname + '/query');
66
var utils = require(__dirname + '/utils');
77

88
var Connection = require(__dirname + '/connection');
@@ -15,10 +15,11 @@ var Client = function(config) {
1515
this.port = config.port || 5432;
1616
this.host = config.host;
1717
this.queryQueue = [];
18-
1918
this.connection = config.connection || new Connection({stream: config.stream || new net.Stream()});
2019
this.queryQueue = [];
2120
this.password = config.password || '';
21+
22+
//internal references only declared here for clarity
2223
this.lastBuffer = false;
2324
this.lastOffset = 0;
2425
this.buffer = null;
@@ -95,181 +96,4 @@ Client.md5 = function(string) {
9596
return crypto.createHash('md5').update(string).digest('hex');
9697
};
9798

98-
var Query = function(config) {
99-
this.text = config.text;
100-
this.values = config.values;
101-
this.rows = config.rows;
102-
this.types = config.types;
103-
this.name = config.name;
104-
//for code clarity purposes we'll declare this here though it's not
105-
//set or used until a rowDescription message comes in
106-
this.rowDescription = null;
107-
EventEmitter.call(this);
108-
};
109-
110-
sys.inherits(Query, EventEmitter);
111-
var p = Query.prototype;
112-
113-
p.requiresPreparation = function() {
114-
return (this.values || 0).length > 0 || this.name || this.rows;
115-
};
116-
117-
p.submit = function(connection) {
118-
var self = this;
119-
if(this.requiresPreparation()) {
120-
this.prepare(connection);
121-
} else {
122-
connection.query(this.text);
123-
}
124-
var handleRowDescription = function(msg) {
125-
self.onRowDescription(msg);
126-
};
127-
var handleDatarow = function(msg) {
128-
self.onDataRow(msg);
129-
};
130-
connection.on('rowDescription', handleRowDescription);
131-
connection.on('dataRow', handleDatarow);
132-
connection.once('readyForQuery', function() {
133-
//remove all listeners
134-
connection.removeListener('rowDescription', handleRowDescription);
135-
connection.removeListener('dataRow', handleDatarow);
136-
self.emit('end');
137-
});
138-
};
139-
140-
p.hasBeenParsed = function(connection) {
141-
return this.name && connection.parsedStatements[this.name];
142-
};
143-
144-
p.prepare = function(connection) {
145-
var self = this;
146-
var onParseComplete = function() {
147-
if(self.values) {
148-
self.values = self.values.map(function(val) {
149-
return (val instanceof Date) ? JSON.stringify(val) : val;
150-
});
151-
}
152-
//http://developer.postgresql.org/pgdocs/postgres/protocol-flow.html#PROTOCOL-FLOW-EXT-QUERY
153-
connection.bind({
154-
portal: self.name,
155-
statement: self.name,
156-
values: self.values
157-
});
158-
connection.describe({
159-
type: 'P',
160-
name: self.name || ""
161-
});
162-
connection.execute({
163-
portal: self.name,
164-
rows: self.rows
165-
});
166-
connection.flush();
167-
};
168-
169-
170-
if(this.hasBeenParsed(connection)) {
171-
onParseComplete();
172-
} else {
173-
connection.parsedStatements[this.name] = true;
174-
connection.parse({
175-
text: self.text,
176-
name: self.name,
177-
types: self.types
178-
});
179-
onParseComplete();
180-
}
181-
182-
183-
//TODO support EmptyQueryResponse, ErrorResponse, and PortalSuspended
184-
var onCommandComplete = function() {
185-
connection.sync();
186-
};
187-
connection.once('commandComplete', onCommandComplete);
188-
189-
};
190-
191-
var noParse = function(val) {
192-
return val;
193-
};
194-
195-
p.onRowDescription = function(msg) {
196-
this.converters = msg.fields.map(function(field) {
197-
return Client.dataTypeParser[field.dataTypeID] || noParse;
198-
});
199-
};
200-
201-
//handles the raw 'dataRow' event from the connection does type coercion
202-
p.onDataRow = function(msg) {
203-
for(var i = 0; i < msg.fields.length; i++) {
204-
if(msg.fields[i] !== null) {
205-
msg.fields[i] = this.converters[i](msg.fields[i]);
206-
}
207-
}
208-
this.emit('row', msg);
209-
};
210-
211-
var dateParser = function(isoDate) {
212-
//TODO find some regexp help
213-
//this method works but it's ooglay
214-
var split = isoDate.split(' ');
215-
var dateMatcher = /(\d{4})-(\d{2})-(\d{2})/;
216-
217-
var date = split[0];
218-
var time = split[1];
219-
var match = dateMatcher.exec(date);
220-
var splitDate = date.split('-');
221-
var year = match[1];
222-
var month = parseInt(match[2])-1;
223-
var day = match[3];
224-
225-
var splitTime = time.split(':');
226-
var hour = parseInt(splitTime[0]);
227-
var min = splitTime[1];
228-
var end = splitTime[2];
229-
var seconds = /(\d{2})/.exec(end);
230-
seconds = (seconds ? seconds[1] : 0);
231-
var mili = /\.(\d{1,})/.exec(end);
232-
mili = mili ? mili[1].slice(0,3) : 0;
233-
var tZone = /([Z|+\-])(\d{2})?(\d{2})?/.exec(end);
234-
//minutes to adjust for timezone
235-
var tzAdjust = 0;
236-
if(tZone) {
237-
var type = tZone[1];
238-
switch(type) {
239-
case 'Z': break;
240-
case '-':
241-
tzAdjust = -(((parseInt(tZone[2])*60)+(parseInt(tZone[3]||0))));
242-
break;
243-
case '+':
244-
tzAdjust = (((parseInt(tZone[2])*60)+(parseInt(tZone[3]||0))));
245-
break;
246-
default:
247-
throw new Error("Unidentifed tZone part " + type);
248-
}
249-
}
250-
251-
var utcOffset = Date.UTC(year, month, day, hour, min, seconds, mili);
252-
253-
var date = new Date(utcOffset - (tzAdjust * 60* 1000));
254-
return date;
255-
};
256-
257-
Client.dataTypeParser = {
258-
20: parseInt,
259-
21: parseInt,
260-
23: parseInt,
261-
26: parseInt,
262-
1700: parseFloat,
263-
700: parseFloat,
264-
701: parseFloat,
265-
16: function(dbVal) { //boolean
266-
return dbVal === 't';
267-
},
268-
// 1083: timeParser,
269-
// 1266: timeParser,
270-
1114: dateParser,
271-
1184: dateParser
272-
};
273-
274-
//end parsing methods
27599
module.exports = Client;

lib/query.js

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
var EventEmitter = require('events').EventEmitter;
2+
3+
var Query = function(config) {
4+
this.text = config.text;
5+
this.values = config.values;
6+
this.rows = config.rows;
7+
this.types = config.types;
8+
this.name = config.name;
9+
//for code clarity purposes we'll declare this here though it's not
10+
//set or used until a rowDescription message comes in
11+
this.rowDescription = null;
12+
EventEmitter.call(this);
13+
};
14+
15+
sys.inherits(Query, EventEmitter);
16+
var p = Query.prototype;
17+
18+
p.requiresPreparation = function() {
19+
return (this.values || 0).length > 0 || this.name || this.rows;
20+
};
21+
22+
23+
var noParse = function(val) {
24+
return val;
25+
};
26+
27+
p.submit = function(connection) {
28+
var self = this;
29+
if(this.requiresPreparation()) {
30+
this.prepare(connection);
31+
} else {
32+
connection.query(this.text);
33+
}
34+
var converters;
35+
var handleRowDescription = function(msg) {
36+
converters = msg.fields.map(function(field) {
37+
return dataTypeParsers[field.dataTypeID] || noParse;
38+
});
39+
};
40+
var handleDatarow = function(msg) {
41+
for(var i = 0; i < msg.fields.length; i++) {
42+
if(msg.fields[i] !== null) {
43+
msg.fields[i] = converters[i](msg.fields[i]);
44+
}
45+
}
46+
self.emit('row', msg);
47+
};
48+
connection.on('rowDescription', handleRowDescription);
49+
connection.on('dataRow', handleDatarow);
50+
connection.once('readyForQuery', function() {
51+
//remove all listeners
52+
connection.removeListener('rowDescription', handleRowDescription);
53+
connection.removeListener('dataRow', handleDatarow);
54+
self.emit('end');
55+
});
56+
};
57+
58+
p.hasBeenParsed = function(connection) {
59+
return this.name && connection.parsedStatements[this.name];
60+
};
61+
62+
p.prepare = function(connection) {
63+
var self = this;
64+
65+
if(!this.hasBeenParsed(connection)) {
66+
connection.parsedStatements[this.name] = true;
67+
connection.parse({
68+
text: self.text,
69+
name: self.name,
70+
types: self.types
71+
});
72+
}
73+
74+
//TODO is there some btter way to prepare values for the database?
75+
if(self.values) {
76+
self.values = self.values.map(function(val) {
77+
return (val instanceof Date) ? JSON.stringify(val) : val;
78+
});
79+
}
80+
81+
//http://developer.postgresql.org/pgdocs/postgres/protocol-flow.html#PROTOCOL-FLOW-EXT-QUERY
82+
connection.bind({
83+
portal: self.name,
84+
statement: self.name,
85+
values: self.values
86+
});
87+
88+
connection.describe({
89+
type: 'P',
90+
name: self.name || ""
91+
});
92+
93+
//TODO test for & support multpile row requests
94+
connection.execute({
95+
portal: self.name,
96+
rows: self.rows
97+
});
98+
99+
connection.flush();
100+
101+
//TODO support EmptyQueryResponse, ErrorResponse, and PortalSuspended
102+
var onCommandComplete = function() {
103+
connection.sync();
104+
};
105+
106+
connection.once('commandComplete', onCommandComplete);
107+
};
108+
109+
var dateParser = function(isoDate) {
110+
//TODO find some regexp help
111+
//this method works but it's ooglay
112+
//if you wanna contribute...... ;)
113+
var split = isoDate.split(' ');
114+
var dateMatcher = /(\d{4})-(\d{2})-(\d{2})/;
115+
116+
var date = split[0];
117+
var time = split[1];
118+
var match = dateMatcher.exec(date);
119+
var splitDate = date.split('-');
120+
var year = match[1];
121+
var month = parseInt(match[2])-1;
122+
var day = match[3];
123+
124+
var splitTime = time.split(':');
125+
var hour = parseInt(splitTime[0]);
126+
var min = splitTime[1];
127+
var end = splitTime[2];
128+
var seconds = /(\d{2})/.exec(end);
129+
seconds = (seconds ? seconds[1] : 0);
130+
var mili = /\.(\d{1,})/.exec(end);
131+
mili = mili ? mili[1].slice(0,3) : 0;
132+
var tZone = /([Z|+\-])(\d{2})?(\d{2})?/.exec(end);
133+
//minutes to adjust for timezone
134+
var tzAdjust = 0;
135+
if(tZone) {
136+
var type = tZone[1];
137+
switch(type) {
138+
case 'Z': break;
139+
case '-':
140+
tzAdjust = -(((parseInt(tZone[2])*60)+(parseInt(tZone[3]||0))));
141+
break;
142+
case '+':
143+
tzAdjust = (((parseInt(tZone[2])*60)+(parseInt(tZone[3]||0))));
144+
break;
145+
default:
146+
throw new Error("Unidentifed tZone part " + type);
147+
}
148+
}
149+
150+
var utcOffset = Date.UTC(year, month, day, hour, min, seconds, mili);
151+
152+
var date = new Date(utcOffset - (tzAdjust * 60* 1000));
153+
return date;
154+
};
155+
156+
var dataTypeParsers = {
157+
20: parseInt,
158+
21: parseInt,
159+
23: parseInt,
160+
26: parseInt,
161+
1700: parseFloat,
162+
700: parseFloat,
163+
701: parseFloat,
164+
16: function(dbVal) { //boolean
165+
return dbVal === 't';
166+
},
167+
1114: dateParser,
168+
1184: dateParser
169+
};
170+
171+
172+
module.exports = Query;

0 commit comments

Comments
 (0)