From bab0382ce76d1dbeb9e4197b40a82b8c09c7f802 Mon Sep 17 00:00:00 2001 From: Brian Carlson Date: Wed, 20 Apr 2011 22:31:04 -0500 Subject: [PATCH 01/11] fixed spelling --- .../unit/connection/outbound-sending-tests.js | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/test/unit/connection/outbound-sending-tests.js b/test/unit/connection/outbound-sending-tests.js index 99357c24..6e38ccb9 100644 --- a/test/unit/connection/outbound-sending-tests.js +++ b/test/unit/connection/outbound-sending-tests.js @@ -5,7 +5,7 @@ var con = new Connection({ stream: stream }); -assert.recieved = function(stream, buffer) { +assert.received = function(stream, buffer) { assert.length(stream.packets, 1); var packet = stream.packets.pop(); assert.equalBuffers(packet, buffer); @@ -16,7 +16,7 @@ test("sends startup message", function() { user: 'brian', database: 'bang' }); - assert.recieved(stream, new BufferList() + assert.received(stream, new BufferList() .addInt16(3) .addInt16(0) .addCString('user') @@ -28,13 +28,13 @@ test("sends startup message", function() { test('sends password message', function() { con.password("!"); - assert.recieved(stream, new BufferList().addCString("!").join(true,'p')); + assert.received(stream, new BufferList().addCString("!").join(true,'p')); }); test('sends query message', function() { var txt = 'select * from boom'; con.query(txt); - assert.recieved(stream, new BufferList().addCString(txt).join(true,'Q')); + assert.received(stream, new BufferList().addCString(txt).join(true,'Q')); }); test('sends parse message', function() { @@ -43,7 +43,7 @@ test('sends parse message', function() { .addCString("") .addCString("!") .addInt16(0).join(true, 'P'); - assert.recieved(stream, expected); + assert.received(stream, expected); }); test('sends parse message with named query', function() { @@ -56,7 +56,7 @@ test('sends parse message with named query', function() { .addCString("boom") .addCString("select * from boom") .addInt16(0).join(true,'P'); - assert.recieved(stream, expected); + assert.received(stream, expected); test('with multiple parameters', function() { con.parse({ @@ -72,7 +72,7 @@ test('sends parse message with named query', function() { .addInt32(2) .addInt32(3) .addInt32(4).join(true,'P'); - assert.recieved(stream, expected); + assert.received(stream, expected); }); }); @@ -87,7 +87,7 @@ test('bind messages', function() { .addInt16(0) .addInt16(0) .join(true,"B"); - assert.recieved(stream, expectedBuffer); + assert.received(stream, expectedBuffer); }); test('with named statement, portal, and values', function() { @@ -110,7 +110,7 @@ test('bind messages', function() { .add(Buffer('zing')) .addInt16(0) .join(true, 'B'); - assert.recieved(stream, expectedBuffer); + assert.received(stream, expectedBuffer); }); }); @@ -123,7 +123,7 @@ test("sends execute message", function() { .addCString('') .addInt32(0) .join(true,'E'); - assert.recieved(stream, expectedBuffer); + assert.received(stream, expectedBuffer); }); test("for named portal with row limit", function() { @@ -135,38 +135,38 @@ test("sends execute message", function() { .addCString("my favorite portal") .addInt32(100) .join(true, 'E'); - assert.recieved(stream, expectedBuffer); + assert.received(stream, expectedBuffer); }); }); test('sends flush command', function() { con.flush(); var expected = new BufferList().join(true, 'H'); - assert.recieved(stream, expected); + assert.received(stream, expected); }); test('sends sync command', function() { con.sync(); var expected = new BufferList().join(true,'S'); - assert.recieved(stream, expected); + assert.received(stream, expected); }); test('sends end command', function() { con.end(); var expected = new Buffer([0x58, 0, 0, 0, 4]); - assert.recieved(stream, expected); + assert.received(stream, expected); }); test('sends describe command',function() { test('describe statement', function() { con.describe({type: 'S', name: 'bang'}); var expected = new BufferList().addChar('S').addCString('bang').join(true, 'D') - assert.recieved(stream, expected); + assert.received(stream, expected); }); test("describe unnamed portal", function() { con.describe({type: 'P'}); var expected = new BufferList().addChar('P').addCString("").join(true, "D"); - assert.recieved(stream, expected); + assert.received(stream, expected); }); }); From c98bb216413d9043cb19412872a60e0051c1bc26 Mon Sep 17 00:00:00 2001 From: Brian Carlson Date: Wed, 20 Apr 2011 22:48:40 -0500 Subject: [PATCH 02/11] failing test for native query with object as first parameter and callback as second parameter --- test/integration/client/api-tests.js | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/test/integration/client/api-tests.js b/test/integration/client/api-tests.js index 7427f671..8788047f 100644 --- a/test/integration/client/api-tests.js +++ b/test/integration/client/api-tests.js @@ -96,8 +96,8 @@ test("query errors are handled and do not bubble if callback is provded", functi client.query("SELECT OISDJF FROM LEIWLISEJLSE", assert.calls(function(err, result) { assert.ok(err); log("query error supplied error to callback") - sink.add(); - })) + sink.add(); + })) })) }) @@ -116,3 +116,16 @@ test('callback is fired once and only once', function() { }) })) }) + +test('can provide callback and config object', function() { + pg.connect(connectionString, assert.calls(function(err, client) { + assert.isNull(err); + client.query({ + name: 'boom', + text: 'select NOW()' + }, assert.calls(function(err, result) { + assert.isNull(err); + assert.equal(result.rows[0].now.getYear(), new Date().getYear()) + })) + })) +}) From eba68017d1aa228ace41e379089d5dd780594d0a Mon Sep 17 00:00:00 2001 From: Brian Carlson Date: Wed, 20 Apr 2011 22:48:50 -0500 Subject: [PATCH 03/11] fix gh27 --- lib/native.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/native.js b/lib/native.js index ac195fd2..9db260cd 100644 --- a/lib/native.js +++ b/lib/native.js @@ -129,6 +129,7 @@ var NativeQuery = function(text, values, callback) { this.text = text.text; this.values = text.values; this.name = text.name; + this.callback = values; } else { this.text = text; this.values = values; From 54d065f4a1f05b799bd7f36ed926e0ab504ea395 Mon Sep 17 00:00:00 2001 From: Edward Faulkner Date: Fri, 29 Apr 2011 10:39:00 -0400 Subject: [PATCH 04/11] Adding a parser for postgres time intervals --- lib/types.js | 31 ++++++++++++++++++- test/unit/client/typed-query-results-tests.js | 21 +++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/lib/types.js b/lib/types.js index 89bc5a01..a43608b6 100644 --- a/lib/types.js +++ b/lib/types.js @@ -18,6 +18,7 @@ var getStringTypeParser = function(oid) { return typeParsers[oid] || noParse; }; + //parses PostgreSQL server formatted date strings into javascript date objects var parseDate = function(isoDate) { //TODO this could do w/ a refactor @@ -86,6 +87,33 @@ var parseStringArray = function(val) { }); }; + +var NUM = '([+-]?\\d+)'; +var YEAR = NUM + '\\s+years?'; +var MON = NUM + '\\s+mons?'; +var DAY = NUM + '\\s+days?'; +var TIME = '([+-])?(\\d\\d):(\\d\\d):(\\d\\d)'; +var INTERVAL = [YEAR,MON,DAY,TIME].map(function(p){ return "("+p+")?" }).join('\\s*'); + + +var parseInterval = function(val) { + if (!val) return {}; + var m = new RegExp(INTERVAL).exec(val); + var i = {}; + if (m[2]) i.years = parseInt(m[2]); + if (m[4]) i.months = parseInt(m[4]); + if (m[6]) i.days = parseInt(m[6]); + if (m[9]) i.hours = parseInt(m[9]); + if (m[10]) i.minutes = parseInt(m[10]); + if (m[11]) i.seconds = parseInt(m[11]); + if (m[8] == '-'){ + if (i.hours) i.hours *= -1; + if (i.minutes) i.minutes *= -1; + if (i.seconds) i.seconds *= -1; + } + return i; +}; + //default string type parser registrations registerStringTypeParser(20, parseInt); registerStringTypeParser(21, parseInt); @@ -99,8 +127,9 @@ registerStringTypeParser(1114, parseDate); registerStringTypeParser(1184, parseDate); registerStringTypeParser(1007, parseIntegerArray); registerStringTypeParser(1009, parseStringArray); +registerStringTypeParser(1186, parseInterval); module.exports = { registerStringTypeParser: registerStringTypeParser, - getStringTypeParser: getStringTypeParser + getStringTypeParser: getStringTypeParser, } diff --git a/test/unit/client/typed-query-results-tests.js b/test/unit/client/typed-query-results-tests.js index 77b3beda..5b5632d9 100644 --- a/test/unit/client/typed-query-results-tests.js +++ b/test/unit/client/typed-query-results-tests.js @@ -98,6 +98,27 @@ test('typed results', function() { expected: function(val) { assert.UTCDate(val, 2010, 9, 31, 0, 0, 0, 0); } + },{ + name: 'interval time', + dataTypeID: 1186, + actual: '01:02:03', + expected: function(val) { + assert.deepEqual(val, {'hours':1, 'minutes':2, 'seconds':3}) + } + },{ + name: 'interval long', + dataTypeID: 1186, + actual: '1 year -32 days', + expected: function(val) { + assert.deepEqual(val, {'years':1, 'days':-32}) + } + },{ + name: 'interval combined negative', + dataTypeID: 1186, + actual: '1 day -00:00:03', + expected: function(val) { + assert.deepEqual(val, {'days':1, 'hours': 0, 'minutes': 0, 'seconds':-3}) + } }]; From 795ef164fb7f204d545949568f60c3ebec6e263b Mon Sep 17 00:00:00 2001 From: Edward Faulkner Date: Fri, 29 Apr 2011 10:52:55 -0400 Subject: [PATCH 05/11] Decided not to include zero fields, for consistency. --- lib/types.js | 4 ++++ test/unit/client/typed-query-results-tests.js | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/types.js b/lib/types.js index a43608b6..7357cef9 100644 --- a/lib/types.js +++ b/lib/types.js @@ -111,6 +111,10 @@ var parseInterval = function(val) { if (i.minutes) i.minutes *= -1; if (i.seconds) i.seconds *= -1; } + for (field in i){ + if (i[field] == 0) + delete i[field]; + } return i; }; diff --git a/test/unit/client/typed-query-results-tests.js b/test/unit/client/typed-query-results-tests.js index 5b5632d9..7143e709 100644 --- a/test/unit/client/typed-query-results-tests.js +++ b/test/unit/client/typed-query-results-tests.js @@ -117,7 +117,7 @@ test('typed results', function() { dataTypeID: 1186, actual: '1 day -00:00:03', expected: function(val) { - assert.deepEqual(val, {'days':1, 'hours': 0, 'minutes': 0, 'seconds':-3}) + assert.deepEqual(val, {'days':1, 'seconds':-3}) } }]; From 844fa5aee950a7f2a10ebf2fff15de34ffd4c5a0 Mon Sep 17 00:00:00 2001 From: brianc Date: Sun, 1 May 2011 17:25:32 -0500 Subject: [PATCH 06/11] updated readme --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index f1217a58..dde2d6e4 100644 --- a/README.md +++ b/README.md @@ -107,6 +107,7 @@ Many thanks to the following: * [pshc](https://github.com/pshc) * [pjornblomqvist](https://github.com/bjornblomqvist) * [JulianBirch](https://github.com/JulianBirch) +* [ef4](https://github.com/ef4) ## Documentation @@ -116,6 +117,11 @@ Still a work in progress, I am trying to flesh out the wiki... ### __PLEASE__ check out the WIKI +## Production Use +* [bayt.com](http://bayt.com) + +_if you use node-postgres in production and would like your site listed here, fork & add it_ + ## Help If you need help or run into _any_ issues getting node-postgres to work on your system please report a bug or contact me directly. I am usually available via google-talk at my github account public email address. From 26a85101ceb51f6b6fbcd2e1128d0aedaf96f760 Mon Sep 17 00:00:00 2001 From: brianc Date: Sun, 1 May 2011 17:26:41 -0500 Subject: [PATCH 07/11] version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 36d66870..1ee2b37c 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { "name": "pg", - "version": "0.4.0", + "version": "0.4.1", "description": "PostgreSQL client - pure javascript & libpq with the same API", "keywords" : ["postgres", "pg", "libpq", "postgre", "database", "rdbms"], "homepage": "http://github.com/brianc/node-postgres", From 0d195223395989d04668b314197ef0aa8bec4ac6 Mon Sep 17 00:00:00 2001 From: brianc Date: Sun, 1 May 2011 21:35:00 -0500 Subject: [PATCH 08/11] code cleanup --- lib/client-pool.js | 18 ------------------ lib/index.js | 1 + 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/lib/client-pool.js b/lib/client-pool.js index 39404a41..ed3793ec 100644 --- a/lib/client-pool.js +++ b/lib/client-pool.js @@ -26,9 +26,6 @@ module.exports = { client.once('error', onError); - //TODO refactor - //i don't like reaching into the client's connection for attaching - //to specific events here client.once('connect', onReady); } @@ -41,15 +38,6 @@ module.exports = { return defaults.poolSize; } - var log = function() { - //do nothing - } - - //for testing - // var log = function() { - // console.log.apply(console, arguments); - // } - var getPooledClient = function(config, callback) { //lookup pool using config as key //TODO this don't work so hot w/ object configs @@ -57,9 +45,7 @@ module.exports = { //create pool if doesn't exist if(!pool) { - //log("creating pool %s", config) pool = clientPools[config] = new Pool(defaults.poolSize, function() { - //log("creating new client in pool %s", config) var client = new Client(config); client.connected = false; return client; @@ -67,7 +53,6 @@ module.exports = { } pool.checkOut(function(err, client) { - //if client already connected just //pass it along to the callback and return if(client.connected) { @@ -92,9 +77,6 @@ module.exports = { client.once('error', onError); - //TODO refactor - //i don't like reaching into the client's connection for attaching - //to specific events here client.once('connect', onReady); client.connect(); diff --git a/lib/index.js b/lib/index.js index 8652df81..d3eddeb0 100644 --- a/lib/index.js +++ b/lib/index.js @@ -11,6 +11,7 @@ module.exports = { defaults: defaults } +//lazy require native as it may not have been built module.exports.__defineGetter__("native", function() { return require(__dirname + '/native'); }) From b18c981a82175e5ae49688aa78052ecbc5773252 Mon Sep 17 00:00:00 2001 From: brianc Date: Sun, 1 May 2011 21:55:31 -0500 Subject: [PATCH 09/11] remove unused functions of pool --- lib/client-pool.js | 32 +------------------------------- lib/utils.js | 13 ++++++------- test/unit/utils-tests.js | 38 +++++++++++++++++++++----------------- 3 files changed, 28 insertions(+), 55 deletions(-) diff --git a/lib/client-pool.js b/lib/client-pool.js index ed3793ec..5a3d3f8a 100644 --- a/lib/client-pool.js +++ b/lib/client-pool.js @@ -4,41 +4,11 @@ var defaults = require(__dirname + '/defaults'); module.exports = { init: function(Client) { - //wrap up common connection management boilerplate - var connect = function(config, callback) { - if(poolEnabled()) { - return getPooledClient(config, callback) - } - - var client = new Client(config); - client.connect(); - - var onError = function(error) { - client.removeListener('connect', onReady); - callback(error); - } - - var onReady = function() { - client.removeListener('error', onError); - callback(null, client); - client.on('drain', client.end.bind(client)); - } - - client.once('error', onError); - - client.once('connect', onReady); - } - - //connection pool global cache var clientPools = { } - var poolEnabled = function() { - return defaults.poolSize; - } - - var getPooledClient = function(config, callback) { + var connect = function(config, callback) { //lookup pool using config as key //TODO this don't work so hot w/ object configs var pool = clientPools[config]; diff --git a/lib/utils.js b/lib/utils.js index 3813ec94..f8c2e12f 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -20,10 +20,15 @@ var Pool = function(maxSize, createFn) { this.items = []; this.waits = []; } + sys.inherits(Pool, events.EventEmitter); + var p = Pool.prototype; p.checkOut = function(callback) { + if(!this.maxSize) { + return callback(null, this.createFn()); + } var len = 0; for(var i = 0, len = this.items.length; i < len; i++) { var item = this.items[i]; @@ -34,13 +39,7 @@ p.checkOut = function(callback) { //check if we can create a new item if(this.items.length < this.maxSize && this.createFn) { var result = this.createFn(); - var item = result; - //create function can return item conforming to interface - //of stored items to allow for create function to create - //checked out items - if(typeof item.checkedIn == "undefined") { - var item = {ref: result, checkedIn: true} - } + var item = {ref: result, checkedIn: true} this.items.push(item); if(item.checkedIn) { return this._pulse(item, callback) diff --git a/test/unit/utils-tests.js b/test/unit/utils-tests.js index 428ef406..cdf3f557 100644 --- a/test/unit/utils-tests.js +++ b/test/unit/utils-tests.js @@ -91,24 +91,28 @@ test('an empty pool', function() { }) }) -test('when creating async new pool members', function() { - var count = 0; - var pool = new Pool(3, function() { - var item = {ref: {name: ++count}, checkedIn: false}; - process.nextTick(function() { - pool.checkIn(item.ref) - }) - return item; +test('a pool with size of zero', function() { + var index = 0; + var pool = new Pool(0, function() { + return index++; }) - test('one request recieves member', function() { + test('checkin does nothing', function() { + index = 0; + pool.checkIn(301813); + assert.equal(pool.checkOut(assert.calls(function(err, item) { + assert.equal(item, 0); + }))); + }) + test('always creates a new item', function() { + index = 0; pool.checkOut(assert.calls(function(err, item) { - assert.equal(item.name, 1) - pool.checkOut(assert.calls(function(err, item) { - assert.equal(item.name, 2) - pool.checkOut(assert.calls(function(err, item) { - assert.equal(item.name, 3) - })) - })) + assert.equal(item, 0); + })) + pool.checkOut(assert.calls(function(err, item) { + assert.equal(item, 1); + })) + pool.checkOut(assert.calls(function(err, item) { + assert.equal(item, 2); })) }) }) @@ -167,7 +171,7 @@ test('normalizing connection info', function() { assert.equal(output.database, process.env.USER); assert.equal(output.port, 5432); }); - + test('uses overridden defaults', function() { defaults.host = "/var/run/postgresql"; defaults.user = "boom"; From 6c7b908367cda97e5a6105e29edfe45542bad35b Mon Sep 17 00:00:00 2001 From: brianc Date: Mon, 2 May 2011 00:16:07 -0500 Subject: [PATCH 10/11] test for pool name caching --- .../connection-pool/unique-name-tests.js | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 test/integration/connection-pool/unique-name-tests.js diff --git a/test/integration/connection-pool/unique-name-tests.js b/test/integration/connection-pool/unique-name-tests.js new file mode 100644 index 00000000..5e613883 --- /dev/null +++ b/test/integration/connection-pool/unique-name-tests.js @@ -0,0 +1,32 @@ +var helper = require(__dirname + '/test-helper'); + +helper.pg.defaults.poolSize = 1; + +var args = { + user: helper.args.user, + password: helper.args.password, + database: helper.args.database, + port: helper.args.port, + host: helper.args.host +} + +helper.pg.connect(args, assert.calls(function(err, client) { + assert.isNull(err); + client.iGotAccessed = true; + client.query("SELECT NOW()") +})) + +var moreArgs = { + user: helper.args.user + "2", + host: helper.args.host, + password: helper.args.password, + database: helper.args.database, + port: helper.args.port, + zomg: true +} + +helper.pg.connect(moreArgs, assert.calls(function(err, client) { + assert.isNull(err); + assert.ok(client.iGotAccessed === true) + client.end(); +})) From a580c8ab8de9241208e3e7ae43b12ef7acf88fd9 Mon Sep 17 00:00:00 2001 From: brianc Date: Mon, 2 May 2011 00:32:30 -0500 Subject: [PATCH 11/11] code cleanup --- lib/index.js | 2 +- lib/native.js | 63 +++++++++++++++++++++++---------------------------- lib/query.js | 5 +--- lib/writer.js | 3 +++ 4 files changed, 33 insertions(+), 40 deletions(-) diff --git a/lib/index.js b/lib/index.js index d3eddeb0..2f84f0a8 100644 --- a/lib/index.js +++ b/lib/index.js @@ -11,7 +11,7 @@ module.exports = { defaults: defaults } -//lazy require native as it may not have been built +//lazy require native module...the c++ may not have been compiled module.exports.__defineGetter__("native", function() { return require(__dirname + '/native'); }) diff --git a/lib/native.js b/lib/native.js index 9db260cd..867ac646 100644 --- a/lib/native.js +++ b/lib/native.js @@ -8,34 +8,6 @@ var types = require(__dirname + "/types"); var Connection = binding.Connection; var p = Connection.prototype; -var add = function(params, config, paramName) { - var value = config[paramName]; - if(value) { - params.push(paramName+"='"+value+"'"); - } -} - -var getLibpgConString = function(config, callback) { - if(typeof config == 'object') { - var params = [] - add(params, config, 'user'); - add(params, config, 'password'); - add(params, config, 'port'); - if(config.database) { - params.push("dbname='" + config.database + "'"); - } - if(config.host) { - if(config.host != 'localhost' && config.host != '127.0.0.1') { - throw new Error("Need to use node to do async DNS on host"); - } - params.push("hostaddr=127.0.0.1 "); - } - callback(params.join(" ")); - } else { - throw new Error("Unrecognized config type for connection"); - } -} - var nativeConnect = p.connect; p.connect = function() { @@ -148,12 +120,13 @@ var NativeQuery = function(text, values, callback) { var item = this.values[i]; if(item instanceof Date) { this.values[i] = JSON.stringify(item); + } else { + this.values[i] = item.toString(); } } } EventEmitter.call(this); - this._translateValues(); }; sys.inherits(NativeQuery, EventEmitter); @@ -194,12 +167,32 @@ p.handleReadyForQuery = function() { this.emit('end'); }; -//translates values into strings -p._translateValues = function() { - if(this.values) { - this.values = this.values.map(function(val) { - return val.toString(); - }); +var add = function(params, config, paramName) { + var value = config[paramName]; + if(value) { + params.push(paramName+"='"+value+"'"); + } +} + +//connection string helper +var getLibpgConString = function(config, callback) { + if(typeof config == 'object') { + var params = [] + add(params, config, 'user'); + add(params, config, 'password'); + add(params, config, 'port'); + if(config.database) { + params.push("dbname='" + config.database + "'"); + } + if(config.host) { + if(config.host != 'localhost' && config.host != '127.0.0.1') { + throw new Error("Need to use node to do async DNS on host"); + } + params.push("hostaddr=127.0.0.1 "); + } + callback(params.join(" ")); + } else { + throw new Error("Unrecognized config type for connection"); } } diff --git a/lib/query.js b/lib/query.js index 0346bd07..f68c343b 100644 --- a/lib/query.js +++ b/lib/query.js @@ -9,9 +9,6 @@ var Query = function(config) { this.rows = config.rows; this.types = config.types; this.name = config.name; - //for code clarity purposes we'll declare this here though it's not - //set or used until a rowDescription message comes in - this.rowDescription = null; this.callback = config.callback; this._fieldNames = []; this._fieldConverters = []; @@ -125,7 +122,7 @@ p.prepare = function(connection) { connection.parsedStatements[this.name] = true; } - //TODO is there some btter way to prepare values for the database? + //TODO is there some better way to prepare values for the database? if(self.values) { self.values = self.values.map(function(val) { return (val instanceof Date) ? JSON.stringify(val) : val; diff --git a/lib/writer.js b/lib/writer.js index 0faf344e..d3f34d28 100644 --- a/lib/writer.js +++ b/lib/writer.js @@ -1,3 +1,6 @@ +//binary data writer tuned for creating +//postgres message packets as effeciently as possible by reusing the +//same buffer to avoid memcpy and limit memory allocations var Writer = function(size) { this.size = size || 1024; this.buffer = new Buffer(this.size + 5);