diff --git a/index.js b/index.js index 3bef4c1..8e48117 100644 --- a/index.js +++ b/index.js @@ -259,11 +259,16 @@ * indexes come from the parsedSql object and a given parameter may * appear in multiple positions. */ - function convertParamValues(parsedSql, values) { + function convertParamValues(parsedSql, values, addUndefinedNamedParameters) { var ret = []; _.each(parsedSql.params, function(param) { if( !_.has(values, param.name) ) { - throw new Error("No value found for parameter: " + param.name); + if(addUndefinedNamedParameters){ + values[param.name] = null; + } + else{ + throw new Error("No value found for parameter: " + param.name); + } } ret.push(values[param.name]); }); @@ -288,7 +293,7 @@ // Add named parameter support to Client.query: var origQuery = pg.Client.prototype.query; - pg.Client.prototype.query = function(config, values, callback) { + pg.Client.prototype.query = function(config, values, callback, addUndefinedNamedParameters) { var sql; if( _.isString(config) ) { sql = config; @@ -304,8 +309,8 @@ throw new Error("First parameter of query() must be a string or config object with a name property"); } var parsedSql = parseSql(sql); - debug.main("parsed sql:", parsedSql); - var params = convertParamValues(parsedSql, values); + debug.main("parsed sql:", parsedSql); + var params = convertParamValues(parsedSql, values, addUndefinedNamedParameters); debug.main("parsed params:", params); return origQuery.apply(this, [parsedSql.sql, params, callback]); } catch( err ) { @@ -326,4 +331,4 @@ "parseSql": parseSql, "convertParamValues": convertParamValues }; -})(); +})(); \ No newline at end of file diff --git a/test/lib/parse-tests.js b/test/lib/parse-tests.js index b8af030..f695ad8 100644 --- a/test/lib/parse-tests.js +++ b/test/lib/parse-tests.js @@ -6,6 +6,7 @@ module.exports = function(spice) { var sql = opts.sql, expectedSql = opts.expectedSql || sql, values = opts.values || {}, + addUndefinedNamedParameters = opts.addUndefinedNamedParameters, expectedNumParams = opts.expectedNumParams || _.size(_.keys(opts.values)); it('should match the expected parsed SQL', function() { var parsed = spice.parseSql(sql); @@ -14,7 +15,7 @@ module.exports = function(spice) { it('should match the expected number of parameters', function() { var parsed = spice.parseSql(sql), - params = spice.convertParamValues(parsed, values); + params = spice.convertParamValues(parsed, values, addUndefinedNamedParameters); assert.equal(params.length, expectedNumParams); }); } @@ -22,11 +23,12 @@ module.exports = function(spice) { function testInvalid(opts) { var text = opts.name || 'should throw an error', sql = opts.sql, + addUndefinedNamedParameters = opts.addUndefinedNamedParameters, values = opts.values || {}; it(text, function() { assert.throws(function() { var parsed = spice.parseSql(sql), - params = spice.convertParamValues(parsed, values); + params = spice.convertParamValues(parsed, values, addUndefinedNamedParameters); }); }); } @@ -84,6 +86,16 @@ module.exports = function(spice) { }); }); + describe('Parse SQL missing parameter value as null', function() { + testValid({ + sql: 'SELECT :foo', + values: {}, + expectedSql:'SELECT $1', + addUndefinedNamedParameters: true, + expectedNumParams : 1 + }); + }); + describe('Parse SQL with existing numbered parameters', function() { testInvalid({ sql: 'SELECT :foo, $1',