From c3f7976203576c7f39aff6af7634cca9bc185375 Mon Sep 17 00:00:00 2001 From: andythiv Date: Wed, 14 Oct 2015 10:42:48 -0700 Subject: [PATCH 1/4] escapeLiteral handles more types of input --- lib/client.js | 55 ++++++++++++++++++++------------ lib/utils.js | 4 ++- test/unit/client/escape-tests.js | 51 +++++++++++++++++++++++++++++ 3 files changed, 89 insertions(+), 21 deletions(-) diff --git a/lib/client.js b/lib/client.js index c888d41b8..1a51d9966 100644 --- a/lib/client.js +++ b/lib/client.js @@ -8,6 +8,7 @@ var ConnectionParameters = require(__dirname + '/connection-parameters'); var Query = require(__dirname + '/query'); var defaults = require(__dirname + '/defaults'); var Connection = require(__dirname + '/connection'); +var utils = require(__dirname + '/utils'); var Client = function(config) { EventEmitter.call(this); @@ -262,31 +263,45 @@ Client.prototype.escapeIdentifier = function(str) { return escaped; }; -// Ported from PostgreSQL 9.2.4 source code in src/interfaces/libpq/fe-exec.c -Client.prototype.escapeLiteral = function(str) { +Client.prototype.escapeLiteral = function(value) { + + if(value === null || value === undefined) { + return 'NULL'; + } else if (typeof value === 'number' || value instanceof Number) { + return value.toString(); + } else if (typeof value === 'boolean' || value instanceof Boolean) { + return value == true ? 'TRUE' : 'FALSE'; + } else if (value instanceof Date){ + return utils.dateToString(value); + } else if (value.constructor === Array) { + return utils.arrayString(value); + } else if(typeof value === 'string' || value instanceof String){ + // Ported from PostgreSQL 9.2.4 source code in src/interfaces/libpq/fe-exec.c + var hasBackslash = false; + var escaped = '\''; + + for(var i = 0; i < value.length; i++) { + var c = value[i]; + if(c === '\'') { + escaped += c + c; + } else if (c === '\\') { + escaped += c + c; + hasBackslash = true; + } else { + escaped += c; + } + } - var hasBackslash = false; - var escaped = '\''; + escaped += '\''; - for(var i = 0; i < str.length; i++) { - var c = str[i]; - if(c === '\'') { - escaped += c + c; - } else if (c === '\\') { - escaped += c + c; - hasBackslash = true; - } else { - escaped += c; + if(hasBackslash === true) { + escaped = ' E' + escaped; } - } - - escaped += '\''; - if(hasBackslash === true) { - escaped = ' E' + escaped; + return escaped; + } else { + return value; } - - return escaped; }; Client.prototype._pulseQueryQueue = function() { diff --git a/lib/utils.js b/lib/utils.js index e28c26af5..226fbcdc5 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -104,5 +104,7 @@ function normalizeQueryConfig (config, values, callback) { module.exports = { prepareValue: prepareValue, - normalizeQueryConfig: normalizeQueryConfig + normalizeQueryConfig: normalizeQueryConfig, + arrayString: arrayString, + dateToString: dateToString }; diff --git a/test/unit/client/escape-tests.js b/test/unit/client/escape-tests.js index e3f638ac1..3e539b837 100644 --- a/test/unit/client/escape-tests.js +++ b/test/unit/client/escape-tests.js @@ -1,4 +1,5 @@ var helper = require(__dirname + '/test-helper'); +var testDateHelper = require('../test-helper'); function createClient(callback) { var client = new Client(helper.config); @@ -47,6 +48,56 @@ testLit('escapeLiteral: contains single quotes and backslashes', testLit('escapeLiteral: contains single quotes, double quotes, and backslashes', 'hello \\ \' " world', " E'hello \\\\ '' \" world'"); +testLit('escapeLiteral: empty string', + '', "''"); + +testLit('escapeLiteral: null', + null, "NULL"); + +testLit('escapeLiteral: undefined', + undefined, "NULL"); + +testLit('escapeLiteral: zero as a string', + '0', "'0'"); + +testLit('escapeLiteral: zero as a number', + 0, "0"); + +testLit('escapeLiteral: number', + 42, "42"); + +testLit('escapeLiteral: Number object', + new Number(88), "88"); + +testLit('escapeLiteral: true', + true, "TRUE"); + +testLit('escapeLiteral: false', + false, "FALSE"); + +testLit('escapeLiteral: true Boolean object', + new Boolean(true), "TRUE"); + +testLit('escapeLiteral: false Boolean object', + new Boolean(false), "FALSE"); + +test('escapeLiteral: Date', function(){ + var d = new Date(); + d.setUTCFullYear(2015, 9, 27); // note: Javascript month range is 0 - 11 + d.setUTCHours(7, 0, 0, 0); + + testDateHelper.setTimezoneOffset(420); + + var client = new Client(helper.config); + var actual = client.escapeLiteral(d); + assert.equal('2015-10-27T00:00:00.000-07:00', actual); + + testDateHelper.resetTimezoneOffset(); +}); + +testLit('escapeLiteral: array', + ['Nintendo', 64], '{"Nintendo","64"}'); + testIdent('escapeIdentifier: no special characters', 'hello world', '"hello world"'); From aafda5e4c307527d8a63f0fb98ab8f9ee2a527ee Mon Sep 17 00:00:00 2001 From: andythiv Date: Wed, 14 Oct 2015 16:20:14 -0700 Subject: [PATCH 2/4] Add jshint ignore and explanation --- lib/client.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/client.js b/lib/client.js index 1a51d9966..b9d179084 100644 --- a/lib/client.js +++ b/lib/client.js @@ -270,7 +270,13 @@ Client.prototype.escapeLiteral = function(value) { } else if (typeof value === 'number' || value instanceof Number) { return value.toString(); } else if (typeof value === 'boolean' || value instanceof Boolean) { - return value == true ? 'TRUE' : 'FALSE'; + /* + Reason for jshint ignore: + jshint normally enforces that an equality check with a boolean literal uses === (triple equals sign). + However, for this instance, we intentionally use == because === will fail when used with a Boolean object type. + The unit tests cover this behavior. + */ + return value == true ? 'TRUE' : 'FALSE'; // jshint ignore:line } else if (value instanceof Date){ return utils.dateToString(value); } else if (value.constructor === Array) { From df6244c8a97436562be99cd80240dcc8b10b4654 Mon Sep 17 00:00:00 2001 From: andythiv Date: Wed, 14 Oct 2015 16:55:09 -0700 Subject: [PATCH 3/4] Fix timezone issue affecting unit test --- test/unit/client/escape-tests.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/test/unit/client/escape-tests.js b/test/unit/client/escape-tests.js index 3e539b837..b1bb86735 100644 --- a/test/unit/client/escape-tests.js +++ b/test/unit/client/escape-tests.js @@ -82,12 +82,10 @@ testLit('escapeLiteral: false Boolean object', new Boolean(false), "FALSE"); test('escapeLiteral: Date', function(){ - var d = new Date(); - d.setUTCFullYear(2015, 9, 27); // note: Javascript month range is 0 - 11 - d.setUTCHours(7, 0, 0, 0); - testDateHelper.setTimezoneOffset(420); + var d = new Date(2015, 9, 27); // note: Javascript month range is 0 - 11 + var client = new Client(helper.config); var actual = client.escapeLiteral(d); assert.equal('2015-10-27T00:00:00.000-07:00', actual); From 10d2cb2399b069f999d9f63926108e37a32ecd97 Mon Sep 17 00:00:00 2001 From: andythiv Date: Fri, 16 Oct 2015 18:52:22 -0700 Subject: [PATCH 4/4] Minor: fixed inconsistent brace spacing style --- lib/client.js | 4 ++-- test/unit/client/escape-tests.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/client.js b/lib/client.js index eb8fb148c..afb5cb0f4 100644 --- a/lib/client.js +++ b/lib/client.js @@ -277,11 +277,11 @@ Client.prototype.escapeLiteral = function(value) { The unit tests cover this behavior. */ return value == true ? 'TRUE' : 'FALSE'; // jshint ignore:line - } else if (value instanceof Date){ + } else if (value instanceof Date) { return utils.dateToString(value); } else if (value.constructor === Array) { return utils.arrayString(value); - } else if(typeof value === 'string' || value instanceof String){ + } else if(typeof value === 'string' || value instanceof String) { // Ported from PostgreSQL 9.2.4 source code in src/interfaces/libpq/fe-exec.c var hasBackslash = false; var escaped = '\''; diff --git a/test/unit/client/escape-tests.js b/test/unit/client/escape-tests.js index b1bb86735..02eb06bdb 100644 --- a/test/unit/client/escape-tests.js +++ b/test/unit/client/escape-tests.js @@ -81,7 +81,7 @@ testLit('escapeLiteral: true Boolean object', testLit('escapeLiteral: false Boolean object', new Boolean(false), "FALSE"); -test('escapeLiteral: Date', function(){ +test('escapeLiteral: Date', function() { testDateHelper.setTimezoneOffset(420); var d = new Date(2015, 9, 27); // note: Javascript month range is 0 - 11