diff --git a/lib/client.js b/lib/client.js index 53b4481d3..8c281725e 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 TypeOverrides = require('./type-overrides'); var ConnectionParameters = require(__dirname + '/connection-parameters'); var Query = require(__dirname + '/query'); @@ -20,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 @@ -227,6 +230,14 @@ Client.prototype.cancel = function(client, query) { } }; +Client.prototype.setTypeParser = function(oid, format, parseFn) { + return this._types.setTypeParser(oid, format, parseFn); +}; + +Client.prototype.getTypeParser = function(oid, format) { + return 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 +313,7 @@ Client.prototype.query = function(config, values, callback) { if(this.binary && !query.binary) { query.binary = true; } + 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 4ca87edc9..7569c4d47 100644 --- a/lib/native/index.js +++ b/lib/native/index.js @@ -1,4 +1,5 @@ var Native = require('pg-native'); +var TypeOverrides = require('../type-overrides'); var semver = require('semver'); var pkg = require('../../package.json'); var assert = require('assert'); @@ -15,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: config.types || require('pg-types') + types: this._types }); this._queryQueue = []; @@ -180,3 +183,11 @@ Client.prototype.cancel = function(query) { this._queryQueue.splice(this._queryQueue.indexOf(query), 1); } }; + +Client.prototype.setTypeParser = function(oid, format, parseFn) { + return this._types.setTypeParser(oid, format, parseFn); +}; + +Client.prototype.getTypeParser = function(oid, format) { + return 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; 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; 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); + })); +}));