From 5fff5fc61fccc1847428d351654f8334231fc363 Mon Sep 17 00:00:00 2001 From: "David H. Bronke" Date: Thu, 13 Nov 2014 17:53:01 -0600 Subject: [PATCH 1/4] Added integration test for overriding type parsers on a per-client basis. --- .../client/type-parser-override-tests.js | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 test/integration/client/type-parser-override-tests.js diff --git a/test/integration/client/type-parser-override-tests.js b/test/integration/client/type-parser-override-tests.js new file mode 100644 index 000000000..68a5de7f7 --- /dev/null +++ b/test/integration/client/type-parser-override-tests.js @@ -0,0 +1,34 @@ +var helper = require(__dirname + '/test-helper'); + +function testTypeParser(client, expectedResult, done) { + var boolValue = true; + client.query('CREATE TEMP TABLE parserOverrideTest(id bool)'); + client.query('INSERT INTO parserOverrideTest(id) VALUES ($1)', [boolValue]); + client.query('SELECT * FROM parserOverrideTest', assert.success(function(result) { + assert.equal(result.rows[0].id, expectedResult); + helper.pg.end(); + done(); + })); +} + +helper.pg.connect(helper.config, assert.success(function(client1, done1) { + helper.pg.connect(helper.config, assert.success(function(client2, done2) { + var boolTypeOID = 16; + client1.setTypeParser(boolTypeOID, function(){ + return 'first client'; + }); + client2.setTypeParser(boolTypeOID, function(){ + return 'second client'; + }); + + client1.setTypeParser(boolTypeOID, 'binary', function(){ + return 'first client binary'; + }); + client2.setTypeParser(boolTypeOID, 'binary', function(){ + return 'second client binary'; + }); + + testTypeParser(client1, 'first client', done1); + testTypeParser(client2, 'second client', done2); + })); +})); From a0bf25e30830898a3f27d3d87cb311c9cc7099c5 Mon Sep 17 00:00:00 2001 From: "David H. Bronke" Date: Thu, 13 Nov 2014 17:57:00 -0600 Subject: [PATCH 2/4] Implemented per-client type parser overrides. Adds Client#getTypeParser() and Client#setTypeParser(). --- lib/client.js | 22 ++++++++++++++++++++++ lib/native/index.js | 23 ++++++++++++++++++++++- lib/result.js | 4 +++- 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/lib/client.js b/lib/client.js index 53b4481d3..636275d8a 100644 --- a/lib/client.js +++ b/lib/client.js @@ -2,6 +2,7 @@ var crypto = require('crypto'); var EventEmitter = require('events').EventEmitter; var util = require('util'); var pgPass = require('pgpass'); +var types = require('pg-types'); var ConnectionParameters = require(__dirname + '/connection-parameters'); var Query = require(__dirname + '/query'); @@ -30,6 +31,12 @@ var Client = function(config) { this.processID = null; this.secretKey = null; this.ssl = this.connectionParameters.ssl || false; + + this._types = config.types || types; + this._parserOverrides = { + text: {}, + binary: {} + }; }; util.inherits(Client, EventEmitter); @@ -227,6 +234,20 @@ Client.prototype.cancel = function(client, query) { } }; +Client.prototype.setTypeParser = function(oid, format, parseFn) { + if(typeof format == 'function') { + parseFn = format; + format = 'text'; + } + this._parserOverrides[format][oid] = parseFn; +}; + +Client.prototype.getTypeParser = function(oid, format) { + format = format || 'text'; + var formatParserOverrides = this._parserOverrides[format] || {}; + return formatParserOverrides[oid] || this._types.getTypeParser(oid, format); +}; + // Ported from PostgreSQL 9.2.4 source code in src/interfaces/libpq/fe-exec.c Client.prototype.escapeIdentifier = function(str) { @@ -302,6 +323,7 @@ Client.prototype.query = function(config, values, callback) { if(this.binary && !query.binary) { query.binary = true; } + query._result._getTypeParser = this.getTypeParser.bind(this); this.queryQueue.push(query); this._pulseQueryQueue(); diff --git a/lib/native/index.js b/lib/native/index.js index 4ca87edc9..9d21dbcd0 100644 --- a/lib/native/index.js +++ b/lib/native/index.js @@ -1,4 +1,5 @@ var Native = require('pg-native'); +var types = require('pg-types'); var semver = require('semver'); var pkg = require('../../package.json'); var assert = require('assert'); @@ -16,7 +17,7 @@ var Client = module.exports = function(config) { config = config || {}; this.native = new Native({ - types: config.types || require('pg-types') + types: {getTypeParser: this.getTypeParser.bind(this)} }); this._queryQueue = []; @@ -33,6 +34,12 @@ var Client = module.exports = function(config) { //a hash to hold named queries this.namedQueries = {}; + + this._types = config.types || types; + this._parserOverrides = { + text: {}, + binary: {} + }; }; util.inherits(Client, EventEmitter); @@ -180,3 +187,17 @@ Client.prototype.cancel = function(query) { this._queryQueue.splice(this._queryQueue.indexOf(query), 1); } }; + +Client.prototype.setTypeParser = function(oid, format, parseFn) { + if(typeof format == 'function') { + parseFn = format; + format = 'text'; + } + this._parserOverrides[format][oid] = parseFn; +}; + +Client.prototype.getTypeParser = function(oid, format) { + format = format || 'text'; + var formatParserOverrides = this._parserOverrides[format] || {}; + return formatParserOverrides[oid] || this._types.getTypeParser(oid, format); +}; diff --git a/lib/result.js b/lib/result.js index ae992551b..bf05381d6 100644 --- a/lib/result.js +++ b/lib/result.js @@ -88,7 +88,7 @@ Result.prototype.addFields = function(fieldDescriptions) { for(var i = 0; i < fieldDescriptions.length; i++) { var desc = fieldDescriptions[i]; this.fields.push(desc); - var parser = types.getTypeParser(desc.dataTypeID, desc.format || 'text'); + var parser = this._getTypeParser(desc.dataTypeID, desc.format || 'text'); this._parsers.push(parser); //this is some craziness to compile the row result parsing //results in ~60% speedup on large query result sets @@ -99,4 +99,6 @@ Result.prototype.addFields = function(fieldDescriptions) { } }; +Result.prototype._getTypeParser = types.getTypeParser; + module.exports = Result; From 857408540c726f6211e19b6ea2b3e338c8c9b081 Mon Sep 17 00:00:00 2001 From: "David H. Bronke" Date: Wed, 3 Dec 2014 10:53:55 -0600 Subject: [PATCH 3/4] Corrected property access on possibly undefined variable. --- lib/client.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/client.js b/lib/client.js index 636275d8a..44ab89cf2 100644 --- a/lib/client.js +++ b/lib/client.js @@ -32,7 +32,7 @@ var Client = function(config) { this.secretKey = null; this.ssl = this.connectionParameters.ssl || false; - this._types = config.types || types; + this._types = c.types || types; this._parserOverrides = { text: {}, binary: {} From 4bfdc041ef4f8b06d2f937c13bf18806682429fb Mon Sep 17 00:00:00 2001 From: "David H. Bronke" Date: Wed, 3 Dec 2014 11:00:27 -0600 Subject: [PATCH 4/4] Moved type override code into a new class. --- lib/client.js | 22 ++++++---------------- lib/native/index.js | 22 ++++++---------------- lib/type-overrides.js | 30 ++++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 32 deletions(-) create mode 100644 lib/type-overrides.js diff --git a/lib/client.js b/lib/client.js index 44ab89cf2..8c281725e 100644 --- a/lib/client.js +++ b/lib/client.js @@ -2,7 +2,7 @@ var crypto = require('crypto'); var EventEmitter = require('events').EventEmitter; var util = require('util'); var pgPass = require('pgpass'); -var types = require('pg-types'); +var TypeOverrides = require('./type-overrides'); var ConnectionParameters = require(__dirname + '/connection-parameters'); var Query = require(__dirname + '/query'); @@ -21,6 +21,8 @@ var Client = function(config) { var c = config || {}; + this._types = new TypeOverrides(c.types); + this.connection = c.connection || new Connection({ stream: c.stream, ssl: this.connectionParameters.ssl @@ -31,12 +33,6 @@ var Client = function(config) { this.processID = null; this.secretKey = null; this.ssl = this.connectionParameters.ssl || false; - - this._types = c.types || types; - this._parserOverrides = { - text: {}, - binary: {} - }; }; util.inherits(Client, EventEmitter); @@ -235,17 +231,11 @@ Client.prototype.cancel = function(client, query) { }; Client.prototype.setTypeParser = function(oid, format, parseFn) { - if(typeof format == 'function') { - parseFn = format; - format = 'text'; - } - this._parserOverrides[format][oid] = parseFn; + return this._types.setTypeParser(oid, format, parseFn); }; Client.prototype.getTypeParser = function(oid, format) { - format = format || 'text'; - var formatParserOverrides = this._parserOverrides[format] || {}; - return formatParserOverrides[oid] || this._types.getTypeParser(oid, format); + return this._types.getTypeParser(oid, format); }; // Ported from PostgreSQL 9.2.4 source code in src/interfaces/libpq/fe-exec.c @@ -323,7 +313,7 @@ Client.prototype.query = function(config, values, callback) { if(this.binary && !query.binary) { query.binary = true; } - query._result._getTypeParser = this.getTypeParser.bind(this); + query._result._getTypeParser = this._types.getTypeParser.bind(this._types); this.queryQueue.push(query); this._pulseQueryQueue(); diff --git a/lib/native/index.js b/lib/native/index.js index 9d21dbcd0..7569c4d47 100644 --- a/lib/native/index.js +++ b/lib/native/index.js @@ -1,5 +1,5 @@ var Native = require('pg-native'); -var types = require('pg-types'); +var TypeOverrides = require('../type-overrides'); var semver = require('semver'); var pkg = require('../../package.json'); var assert = require('assert'); @@ -16,8 +16,10 @@ var Client = module.exports = function(config) { EventEmitter.call(this); config = config || {}; + this._types = new TypeOverrides(config.types); + this.native = new Native({ - types: {getTypeParser: this.getTypeParser.bind(this)} + types: this._types }); this._queryQueue = []; @@ -34,12 +36,6 @@ var Client = module.exports = function(config) { //a hash to hold named queries this.namedQueries = {}; - - this._types = config.types || types; - this._parserOverrides = { - text: {}, - binary: {} - }; }; util.inherits(Client, EventEmitter); @@ -189,15 +185,9 @@ Client.prototype.cancel = function(query) { }; Client.prototype.setTypeParser = function(oid, format, parseFn) { - if(typeof format == 'function') { - parseFn = format; - format = 'text'; - } - this._parserOverrides[format][oid] = parseFn; + return this._types.setTypeParser(oid, format, parseFn); }; Client.prototype.getTypeParser = function(oid, format) { - format = format || 'text'; - var formatParserOverrides = this._parserOverrides[format] || {}; - return formatParserOverrides[oid] || this._types.getTypeParser(oid, format); + return this._types.getTypeParser(oid, format); }; diff --git a/lib/type-overrides.js b/lib/type-overrides.js new file mode 100644 index 000000000..f6ebdb97e --- /dev/null +++ b/lib/type-overrides.js @@ -0,0 +1,30 @@ +var types = require('pg-types'); + +function TypeOverrides(userTypes) { + this._types = userTypes || types; + this.text = {}; + this.binary = {}; +} + +TypeOverrides.prototype.getOverrides = function(format) { + switch(format) { + case 'text': return this.text; + case 'binary': return this.binary; + default: return {}; + } +}; + +TypeOverrides.prototype.setTypeParser = function(oid, format, parseFn) { + if(typeof format == 'function') { + parseFn = format; + format = 'text'; + } + this.getOverrides(format)[oid] = parseFn; +}; + +TypeOverrides.prototype.getTypeParser = function(oid, format) { + format = format || 'text'; + return this.getOverrides(format)[oid] || this._types.getTypeParser(oid, format); +}; + +module.exports = TypeOverrides;