From c68c365478b5b6b759a389db2a29050e468b7eda Mon Sep 17 00:00:00 2001 From: brianc Date: Wed, 29 Sep 2010 01:01:52 -0500 Subject: [PATCH] working on getting query to complete --- lib/index.js | 64 ++++++++++++++++++++++++++++++++++++++------ test/api-tests.js | 9 +++---- test/parser-tests.js | 40 +++++++++++++++++++++++---- test/test-helper.js | 7 ++++- watch.rb | 4 ++- 5 files changed, 103 insertions(+), 21 deletions(-) diff --git a/lib/index.js b/lib/index.js index 0d6e1753..054115cc 100644 --- a/lib/index.js +++ b/lib/index.js @@ -3,12 +3,14 @@ var sys = require('sys'); var net = require('net'); var NUL = '\0'; -var chars = Buffer('RSKZ','utf8'); +var chars = Buffer('RSKZQC','utf8'); var UTF8 = { R: chars[0], S: chars[1], K: chars[2], - Z: chars[3] + Z: chars[3], + Q: chars[4], + C: chars[5] }; @@ -18,6 +20,7 @@ var Client = function(config) { this.user = config.user; this.database = config.database; this.port = config.port || 5432; + this.queryQueue = []; }; sys.inherits(Client, EventEmitter); @@ -25,7 +28,6 @@ Client.prototype.connect = function() { var con = net.createConnection(this.port); var self = this; con.on('connect', function() { - var data = ['user',self.user,'database', self.database,NUL].join(NUL); var dataBuffer = Buffer(data); var fullBuffer = Buffer(8 + dataBuffer.length); @@ -38,19 +40,57 @@ Client.prototype.connect = function() { fullBuffer[6] = 0; fullBuffer[7] = 0; fullBuffer.write(data,8); - console.log(fullBuffer); con.write(fullBuffer); }); con.on('data', function(data) { - console.log('data!'); - console.log(data); var parser = new Parser(data); - con.end(); var result = parser.parse(); result.forEach(function(msg) { - console.log(msg); + self.emit('message', msg); + self.emit(msg.name, msg); }); }); + this.con = con; + this.on('ReadyForQuery', function() { + self.readyForQuery = true; + self.pulseQueryQueue(); + }); + this.on('message', function(msg) { + console.log(msg.name); + }); +}; + +Client.prototype.query = function(queryText) { + this.queryQueue.push(new Query({ + text: queryText + })); + this.pulseQueryQueue(); +}; + +Client.prototype.pulseQueryQueue = function() { + if(!this.readyForQuery) { + return; + } + var query = this.queryQueue.shift(); + if(!query) { + return; + } + var txt = query.text + "\0" + var queryTextBuffer = Buffer(txt); + var len = queryTextBuffer.length+4; + var messageBuffer = Buffer(queryTextBuffer.length + 5); + messageBuffer[0] = UTF8.Q; + messageBuffer[1] = len >>> 24; + messageBuffer[2] = len >>> 16; + messageBuffer[3] = len >>> 8; + messageBuffer[4] = len >>> 0; + messageBuffer.write(txt,5); + this.con.write(messageBuffer); + this.readyForQuery = false; +}; + +var Query = function(config) { + this.text = config.text; }; var Parser = function(buffer) { @@ -83,6 +123,8 @@ p.parseMessage = function() { return this.parseK(); case UTF8.Z: return this.parseZ(); + case UTF8.C: + return this.parseC(); default: throw new Error("Unsupported message ID: " + Buffer([messageID]).toString('utf8') + " (" + messageID.toString(16) + ")"); } @@ -116,6 +158,12 @@ p.parseK = function() { return msg; }; +p.parseC = function() { + var msg = this.parseStart('CommandComplete'); + msg.text = this.parseCString(); + return msg; +}; + //parses common start of message packets p.parseStart = function(name) { return { diff --git a/test/api-tests.js b/test/api-tests.js index 202a1e05..622ee31f 100644 --- a/test/api-tests.js +++ b/test/api-tests.js @@ -20,10 +20,7 @@ assert.equal(client.database, 'hello'); assert.equal(client.port, 321); client.port = 5432; -client.connect(function() { - console.log('connected'); - client.query('select count(*) from items',function(result) { - console.log('ran query'); - }); -}); +client.connect(); + +var query = client.query('create temporary table bang (id integer)'); diff --git a/test/parser-tests.js b/test/parser-tests.js index 838c0fa4..27a7d6f7 100644 --- a/test/parser-tests.js +++ b/test/parser-tests.js @@ -1,15 +1,18 @@ require(__dirname+'/test-helper'); test('Parser on single messages', function() { - var authenticationOkBuffer = Buffer([0x52, 00, 00, 00, 08, 00, 00, 00, 00]); + var authOkData = [0x52, 00, 00, 00, 08, 00, 00, 00, 00]; + var authenticationOkBuffer = Buffer(authOkData); var firstString = [0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0]; var secondString = [0x55, 0x54, 0x46, 0x38, 0]; - var bytes = [0x53, 0, 0, 0, 0x19].concat(firstString).concat(secondString); - var parameterStatusBuffer = Buffer(bytes); + var paramStatusData = [0x53, 0, 0, 0, 0x19].concat(firstString).concat(secondString); + var parameterStatusBuffer = Buffer(paramStatusData); - var backendKeyDataBuffer = Buffer([0x4b, 0, 0, 0, 0x0c, 0, 0, 0, 1, 0, 0, 0, 2]); + var backendKeyData = [0x4b, 0, 0, 0, 0x0c, 0, 0, 0, 1, 0, 0, 0, 2]; + var backendKeyDataBuffer = Buffer(backendKeyData); - var readyForQueryBuffer = Buffer([0x5a, 0, 0, 0, 5, 'I'.charCodeAt(0)]) + var readyForQueryData = [0x5a, 0, 0, 0, 5, 'I'.charCodeAt(0)]; + var readyForQueryBuffer = Buffer(readyForQueryData) var expectedAuthenticationOkayMessage = { @@ -60,10 +63,37 @@ test('Parser on single messages', function() { assert.same(result, expectedReadyForQueryMessage); }); + test('parses multiple messages', function() { + var message = authOkData + .concat(paramStatusData) + .concat(backendKeyData) + .concat(readyForQueryData); + var buffer = Buffer(message); + var result = new Parser(buffer).parse(); + assert.equal(result.length, 4); + assert.same(result[0], expectedAuthenticationOkayMessage); + assert.same(result[1], expectedParameterStatusMessage); + assert.same(result[2], expectedBackendKeyDataMessage); + assert.same(result[3], expectedReadyForQueryMessage); + }); + test('parses normal CString', function() { var result = new Parser(Buffer([33,0])).parseCString(); assert.equal(result,"!"); }); + + var resultText = stringToHex("SELECT 3\0"); + var length = resultText.length + 4; + var commandCompleteData = [0x43, 0, 0, 0, length].concat(resultText); + + test('parses CommandComplete message', function() { + var result = new Parser(Buffer(commandCompleteData)).parse()[0]; + assert.same(result, { + length: 13, + id: 'C', + text: "SELECT 3" + }); + }); test('parses empty CString', function() { var result = new Parser(Buffer([0])).parseCString(); diff --git a/test/test-helper.js b/test/test-helper.js index 0e08b940..e7b995e4 100644 --- a/test/test-helper.js +++ b/test/test-helper.js @@ -23,7 +23,12 @@ test = function(name, action) { test.tabout = 0; stringToHex = function(string) { - + var b = Buffer(string,'utf8'); + var result = []; + for(var i = 0; i < b.length; i++) { + result.push(b[i]); + } + return result; }; hexToString = function(hexArray) { diff --git a/watch.rb b/watch.rb index 9f1d3eb4..91c2ba1e 100644 --- a/watch.rb +++ b/watch.rb @@ -3,14 +3,16 @@ def run_parser_tests system("node test/parser-tests.js") puts "" - puts("waiting...") + puts("#{Time.now} waiting...") puts "" end watch('lib/(.*)\.js') { |md| + puts "lib changed" run_parser_tests } watch('test/(.*)\.js') { |md| + puts "test changed" run_parser_tests }