(function () { var _ = require('underscore'); function sanitize_input(input) { // http://www.postgresql.org/docs/9.0/static/sql-syntax-lexical.html [4.1.2.1-4.1.2.2] // single quotes (') must be replaced with double single quotes ('') input = input.replace(/'/g, '\'\''); // backslashes (\) must be replaced with double backslashes (\\) input = input.replace(/\\/g, '\\\\'); // double quotes (") must be replaced with escaped quotes (\\") input = input.replace(/"/g, '\\"'); return input; } function to_string(input, sanitize) { switch(typeof input) { case 'boolean': case 'number': case 'object': return String(input); case 'string': return sanitize ? sanitize_input(input) : input; default: return ''; } } module.exports = function (options) { options = _.defaults({}, options, { sanitize: false }); return { stringify: function (data, callback) { var hstore = Object.keys(data).map(function (key) { if (data[key] === null) { return '"'+to_string(key, options.sanitize)+'"=>NULL'; } else { return '"'+to_string(key, options.sanitize)+'"=>"'+to_string(data[key], options.sanitize)+'"'; } }); var joined = hstore.join(); if (!callback || callback === null) return joined; callback(joined); }, parse: function(string, callback) { var result = {}, //using [\s\S] to match any character, including line feed and carriage return, r = /(["])(?:\\\1|\\\\|[\s\S])*?\1|NULL/g, matches = string.match(r), i, l, clean = function (value) { // Remove leading double quotes value = value.replace(/^\"|\"$/g, ""); // Unescape quotes value = value.replace(/\\"/g, "\""); //Unescape backslashes value = value.replace(/\\\\/g,"\\"); //Unescape single quotes value = value.replace(/''/g,"'"); return value; }; if(matches) { for (i = 0, l = matches.length; i < l; i+= 2) { if (matches[i] && matches[i + 1]) { var key = clean(matches[i]); var value = matches[i + 1]; result[key] = value=="NULL"?null:clean(value); } } } if (!callback || callback === null) return result; callback(result); } }; }; })();