diff --git a/lib/defaults.js b/lib/defaults.js index 1241703fd..9f5687b05 100644 --- a/lib/defaults.js +++ b/lib/defaults.js @@ -46,5 +46,5 @@ var defaults = module.exports = { //parse int8 so you can get your count values as actual numbers module.exports.__defineSetter__("parseInt8", function(val) { - require('./types').setTypeParser(20, 'text', val ? parseInt : function(val) { return val; }); + require('pg-types').setTypeParser(20, 'text', val ? parseInt : function(val) { return val; }); }); diff --git a/lib/index.js b/lib/index.js index 423c3ed30..3d7aa5807 100644 --- a/lib/index.js +++ b/lib/index.js @@ -3,7 +3,6 @@ var util = require('util'); var Client = require(__dirname+'/client'); var defaults = require(__dirname + '/defaults'); var pool = require(__dirname + '/pool'); -var types = require(__dirname + '/types/'); var Connection = require(__dirname + '/connection'); var PG = function(clientConstructor) { @@ -12,8 +11,8 @@ var PG = function(clientConstructor) { this.Client = pool.Client = clientConstructor; this.Query = this.Client.Query; this.pools = pool; - this.types = types; this.Connection = Connection; + this.types = require('pg-types'); }; util.inherits(PG, EventEmitter); diff --git a/lib/native/query.js b/lib/native/query.js index d2b06b8e9..9b1a730bc 100644 --- a/lib/native/query.js +++ b/lib/native/query.js @@ -1,7 +1,6 @@ var EventEmitter = require('events').EventEmitter; var util = require('util'); -var types = require(__dirname + '/../types/'); var utils = require(__dirname + '/../utils'); var Result = require(__dirname + '/../result'); diff --git a/lib/query.js b/lib/query.js index c8d2db1eb..c595eda6b 100644 --- a/lib/query.js +++ b/lib/query.js @@ -2,7 +2,6 @@ var EventEmitter = require('events').EventEmitter; var util = require('util'); var Result = require(__dirname + '/result'); -var Types = require(__dirname + '/types/'); var utils = require(__dirname + '/utils'); var Query = function(config, values, callback) { diff --git a/lib/result.js b/lib/result.js index 8ec3de01f..f6c33cc42 100644 --- a/lib/result.js +++ b/lib/result.js @@ -1,4 +1,4 @@ -var types = require(__dirname + '/types/'); +var types = require('pg-types'); //result object returned from query //in the 'end' event and also diff --git a/lib/types/arrayParser.js b/lib/types/arrayParser.js deleted file mode 100644 index 96a37b93b..000000000 --- a/lib/types/arrayParser.js +++ /dev/null @@ -1,97 +0,0 @@ -function ArrayParser(source, converter) { - this.source = source; - this.converter = converter; - this.pos = 0; - this.entries = []; - this.recorded = []; - this.dimension = 0; - if (!this.converter) { - this.converter = function(entry) { - return entry; - }; - } -} - -ArrayParser.prototype.eof = function() { - return this.pos >= this.source.length; -}; - -ArrayParser.prototype.nextChar = function() { - var c; - if ((c = this.source[this.pos++]) === "\\") { - return { - char: this.source[this.pos++], - escaped: true - }; - } else { - return { - char: c, - escaped: false - }; - } -}; - -ArrayParser.prototype.record = function(c) { - return this.recorded.push(c); -}; - -ArrayParser.prototype.newEntry = function(includeEmpty) { - var entry; - if (this.recorded.length > 0 || includeEmpty) { - entry = this.recorded.join(""); - if (entry === "NULL" && !includeEmpty) { - entry = null; - } - if (entry !== null) { - entry = this.converter(entry); - } - this.entries.push(entry); - this.recorded = []; - } -}; - -ArrayParser.prototype.parse = function(nested) { - var c, p, quote; - if (nested === null) { - nested = false; - } - quote = false; - while (!this.eof()) { - c = this.nextChar(); - if (c.char === "{" && !quote) { - this.dimension++; - if (this.dimension > 1) { - p = new ArrayParser(this.source.substr(this.pos - 1), this.converter); - this.entries.push(p.parse(true)); - this.pos += p.pos - 2; - } - } else if (c.char === "}" && !quote) { - this.dimension--; - if (this.dimension === 0) { - this.newEntry(); - if (nested) { - return this.entries; - } - } - } else if (c.char === '"' && !c.escaped) { - if (quote) { - this.newEntry(true); - } - quote = !quote; - } else if (c.char === ',' && !quote) { - this.newEntry(); - } else { - this.record(c.char); - } - } - if (this.dimension !== 0) { - throw "array dimension not balanced"; - } - return this.entries; -}; - -module.exports = { - create: function(source, converter){ - return new ArrayParser(source, converter); - } -}; diff --git a/lib/types/binaryParsers.js b/lib/types/binaryParsers.js deleted file mode 100644 index a71ebb7cb..000000000 --- a/lib/types/binaryParsers.js +++ /dev/null @@ -1,256 +0,0 @@ -var parseBits = function(data, bits, offset, invert, callback) { - offset = offset || 0; - invert = invert || false; - callback = callback || function(lastValue, newValue, bits) { return (lastValue * Math.pow(2, bits)) + newValue; }; - var offsetBytes = offset >> 3; - - var inv = function(value) { - if (invert) { - return ~value & 0xff; - } - - return value; - }; - - // read first (maybe partial) byte - var mask = 0xff; - var firstBits = 8 - (offset % 8); - if (bits < firstBits) { - mask = (0xff << (8 - bits)) & 0xff; - firstBits = bits; - } - - if (offset) { - mask = mask >> (offset % 8); - } - - var result = 0; - if ((offset % 8) + bits >= 8) { - result = callback(0, inv(data[offsetBytes]) & mask, firstBits); - } - - // read bytes - var bytes = (bits + offset) >> 3; - for (var i = offsetBytes + 1; i < bytes; i++) { - result = callback(result, inv(data[i]), 8); - } - - // bits to read, that are not a complete byte - var lastBits = (bits + offset) % 8; - if (lastBits > 0) { - result = callback(result, inv(data[bytes]) >> (8 - lastBits), lastBits); - } - - return result; -}; - -var parseFloatFromBits = function(data, precisionBits, exponentBits) { - var bias = Math.pow(2, exponentBits - 1) - 1; - var sign = parseBits(data, 1); - var exponent = parseBits(data, exponentBits, 1); - - if (exponent === 0) { - return 0; - } - - // parse mantissa - var precisionBitsCounter = 1; - var parsePrecisionBits = function(lastValue, newValue, bits) { - if (lastValue === 0) { - lastValue = 1; - } - - for (var i = 1; i <= bits; i++) { - precisionBitsCounter /= 2; - if ((newValue & (0x1 << (bits - i))) > 0) { - lastValue += precisionBitsCounter; - } - } - - return lastValue; - }; - - var mantissa = parseBits(data, precisionBits, exponentBits + 1, false, parsePrecisionBits); - - // special cases - if (exponent == (Math.pow(2, exponentBits + 1) - 1)) { - if (mantissa === 0) { - return (sign === 0) ? Infinity : -Infinity; - } - - return NaN; - } - - // normale number - return ((sign === 0) ? 1 : -1) * Math.pow(2, exponent - bias) * mantissa; -}; - -var parseBool = function(value) { - return (parseBits(value, 8) == 1); -}; - -var parseInt16 = function(value) { - if (parseBits(value, 1) == 1) { - return -1 * (parseBits(value, 15, 1, true) + 1); - } - - return parseBits(value, 15, 1); -}; - -var parseInt32 = function(value) { - if (parseBits(value, 1) == 1) { - return -1 * (parseBits(value, 31, 1, true) + 1); - } - - return parseBits(value, 31, 1); -}; - -var parseFloat32 = function(value) { - return parseFloatFromBits(value, 23, 8); -}; - -var parseFloat64 = function(value) { - return parseFloatFromBits(value, 52, 11); -}; - -var parseNumeric = function(value) { - var sign = parseBits(value, 16, 32); - if (sign == 0xc000) { - return NaN; - } - - var weight = Math.pow(10000, parseBits(value, 16, 16)); - var result = 0; - - var digits = []; - var ndigits = parseBits(value, 16); - for (var i = 0; i < ndigits; i++) { - result += parseBits(value, 16, 64 + (16 * i)) * weight; - weight /= 10000; - } - - var scale = Math.pow(10, parseBits(value, 16, 48)); - return ((sign === 0) ? 1 : -1) * Math.round(result * scale) / scale; -}; - -var parseDate = function(isUTC, value) { - var sign = parseBits(value, 1); - var rawValue = parseBits(value, 63, 1); - - // discard usecs and shift from 2000 to 1970 - var result = new Date((((sign === 0) ? 1 : -1) * rawValue / 1000) + 946684800000); - - if (!isUTC) { - result.setTime(result.getTime() + result.getTimezoneOffset() * 60000); - } - - // add microseconds to the date - result.usec = rawValue % 1000; - result.getMicroSeconds = function() { - return this.usec; - }; - result.setMicroSeconds = function(value) { - this.usec = value; - }; - result.getUTCMicroSeconds = function() { - return this.usec; - }; - - return result; -}; - -var parseArray = function(value) { - var dim = parseBits(value, 32); - - var flags = parseBits(value, 32, 32); - var elementType = parseBits(value, 32, 64); - - var offset = 96; - var dims = []; - for (var i = 0; i < dim; i++) { - // parse dimension - dims[i] = parseBits(value, 32, offset); - offset += 32; - - // ignore lower bounds - offset += 32; - } - - var parseElement = function(elementType) { - // parse content length - var length = parseBits(value, 32, offset); - offset += 32; - - // parse null values - if (length == 0xffffffff) { - return null; - } - - var result; - if ((elementType == 0x17) || (elementType == 0x14)) { - // int/bigint - result = parseBits(value, length * 8, offset); - offset += length * 8; - return result; - } - else if (elementType == 0x19) { - // string - result = value.toString(this.encoding, offset >> 3, (offset += (length << 3)) >> 3); - return result; - } - else { - console.log("ERROR: ElementType not implemented: " + elementType); - } - }; - - var parse = function(dimension, elementType) { - var array = []; - var i; - - if (dimension.length > 1) { - var count = dimension.shift(); - for (i = 0; i < count; i++) { - array[i] = parse(dimension, elementType); - } - dimension.unshift(count); - } - else { - for (i = 0; i < dimension[0]; i++) { - array[i] = parseElement(elementType); - } - } - - return array; - }; - - return parse(dims, elementType); -}; - -var parseText = function(value) { - return value.toString('utf8'); -}; - -var parseBool = function(value) { - return (parseBits(value, 8) > 0); -}; - -var init = function(register) { - register(21, parseInt16); - register(23, parseInt32); - register(26, parseInt32); - register(1700, parseNumeric); - register(700, parseFloat32); - register(701, parseFloat64); - register(16, parseBool); - register(1114, parseDate.bind(null, false)); - register(1184, parseDate.bind(null, true)); - register(1007, parseArray); - register(1016, parseArray); - register(1008, parseArray); - register(1009, parseArray); - register(25, parseText); -}; - -module.exports = { - init: init -}; diff --git a/lib/types/index.js b/lib/types/index.js deleted file mode 100644 index 0750856c1..000000000 --- a/lib/types/index.js +++ /dev/null @@ -1,44 +0,0 @@ -var textParsers = require(__dirname + '/textParsers'); -var binaryParsers = require(__dirname + '/binaryParsers'); - -var typeParsers = { - text: {}, - binary: {} -}; - -//the empty parse function -var noParse = function(val) { - return String(val); -}; - -//returns a function used to convert a specific type (specified by -//oid) into a result javascript type -//note: the oid can be obtained via the following sql query: -//SELECT oid FROM pg_type WHERE typname = 'TYPE_NAME_HERE'; -var getTypeParser = function(oid, format) { - if (!typeParsers[format]) { - return noParse; - } - return typeParsers[format][oid] || noParse; -}; - -var setTypeParser = function(oid, format, parseFn) { - if(typeof format == 'function') { - parseFn = format; - format = 'text'; - } - typeParsers[format][oid] = parseFn; -}; - -textParsers.init(function(oid, converter) { - typeParsers.text[oid] = converter; -}); - -binaryParsers.init(function(oid, converter) { - typeParsers.binary[oid] = converter; -}); - -module.exports = { - getTypeParser: getTypeParser, - setTypeParser: setTypeParser -}; diff --git a/lib/types/textParsers.js b/lib/types/textParsers.js deleted file mode 100644 index cd16a1f98..000000000 --- a/lib/types/textParsers.js +++ /dev/null @@ -1,238 +0,0 @@ -var arrayParser = require(__dirname + "/arrayParser.js"); - -//parses PostgreSQL server formatted date strings into javascript date objects -var parseDate = function(isoDate) { - //TODO this could do w/ a refactor - var dateMatcher = /(\d{1,})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})(\.\d{1,})?/; - - var match = dateMatcher.exec(isoDate); - //could not parse date - if(!match) { - dateMatcher = /^(\d{1,})-(\d{2})-(\d{2})$/; - match = dateMatcher.test(isoDate); - if(!match) { - return null; - } else { - //it is a date in YYYY-MM-DD format - //add time portion to force js to parse as local time - return new Date(isoDate + ' 00:00:00'); - } - } - var isBC = /BC$/.test(isoDate); - var _year = parseInt(match[1], 10); - var isFirstCentury = (_year > 0) && (_year < 100); - var year = (isBC ? "-" : "") + match[1]; - - var month = parseInt(match[2],10)-1; - var day = match[3]; - var hour = parseInt(match[4],10); - var min = parseInt(match[5],10); - var seconds = parseInt(match[6], 10); - - var miliString = match[7]; - var mili = 0; - if(miliString) { - mili = 1000 * parseFloat(miliString); - } - - //match timezones like the following: - //Z (UTC) - //-05 - //+06:30 - var tZone = /([Z|+\-])(\d{2})?:?(\d{2})?/.exec(isoDate.split(' ')[1]); - //minutes to adjust for timezone - var tzAdjust = 0; - var date; - if(tZone) { - var type = tZone[1]; - switch(type) { - case 'Z': - break; - case '-': - tzAdjust = -(((parseInt(tZone[2],10)*60)+(parseInt(tZone[3]||0,10)))); - break; - case '+': - tzAdjust = (((parseInt(tZone[2],10)*60)+(parseInt(tZone[3]||0,10)))); - break; - default: - throw new Error("Unidentifed tZone part " + type); - } - - var utcOffset = Date.UTC(year, month, day, hour, min, seconds, mili); - - date = new Date(utcOffset - (tzAdjust * 60* 1000)); - } - //no timezone information - else { - date = new Date(year, month, day, hour, min, seconds, mili); - } - - if (isFirstCentury) { - date.setUTCFullYear(year); - } - - return date; -}; - -var parseBool = function(val) { - return val === 't'; -}; - -var parseIntegerArray = function(val) { - if(!val) { return null; } - var p = arrayParser.create(val, function(entry){ - if(entry !== null) { - entry = parseInt(entry, 10); - } - return entry; - }); - - return p.parse(); -}; - -var parseBigIntegerArray = function(val) { - if(!val) { return null; } - var p = arrayParser.create(val, function(entry){ - if(entry !== null) { - entry = parseBigInteger(entry).trim(); - } - return entry; - }); - - return p.parse(); -}; - -var parseFloatArray = function(val) { - if(!val) { return null; } - var p = arrayParser.create(val, function(entry) { - if(entry !== null) { - entry = parseFloat(entry); - } - return entry; - }); - - return p.parse(); -}; - -var parseStringArray = function(val) { - if(!val) { return null; } - - var p = arrayParser.create(val); - return p.parse(); -}; - - -var NUM = '([+-]?\\d+)'; -var YEAR = NUM + '\\s+years?'; -var MON = NUM + '\\s+mons?'; -var DAY = NUM + '\\s+days?'; -var TIME = '([+-])?(\\d\\d):(\\d\\d):(\\d\\d)'; -var INTERVAL = [YEAR,MON,DAY,TIME].map(function(p){ - return "("+p+")?"; -}).join('\\s*'); - -var parseInterval = function(val) { - if (!val) { return {}; } - var m = new RegExp(INTERVAL).exec(val); - var i = {}; - if (m[2]) { i.years = parseInt(m[2], 10); } - if (m[4]) { i.months = parseInt(m[4], 10); } - if (m[6]) { i.days = parseInt(m[6], 10); } - if (m[9]) { i.hours = parseInt(m[9], 10); } - if (m[10]) { i.minutes = parseInt(m[10], 10); } - if (m[11]) { i.seconds = parseInt(m[11], 10); } - if (m[8] == '-'){ - if (i.hours) { i.hours *= -1; } - if (i.minutes) { i.minutes *= -1; } - if (i.seconds) { i.seconds *= -1; } - } - for (var field in i){ - if (i[field] === 0) { - delete i[field]; - } - } - return i; -}; - -var parseByteA = function(val) { - if(/^\\x/.test(val)){ - // new 'hex' style response (pg >9.0) - return new Buffer(val.substr(2), 'hex'); - }else{ - var out = ""; - var i = 0; - while(i < val.length){ - if(val[i] != "\\"){ - out += val[i]; - ++i; - }else{ - if(val.substr(i+1,3).match(/[0-7]{3}/)){ - out += String.fromCharCode(parseInt(val.substr(i+1,3),8)); - i += 4; - }else{ - backslashes = 1; - while(i+backslashes < val.length && val[i+backslashes] == "\\") - backslashes++; - for(k=0; k<Math.floor(backslashes/2); ++k) - out += "\\"; - i += Math.floor(backslashes / 2) * 2; - } - } - } - return new Buffer(out,"binary"); - } -}; - -var maxLen = Number.MAX_VALUE.toString().length; - -var parseInteger = function(val) { - return parseInt(val, 10); -}; - -var parseBigInteger = function(val) { - var valStr = String(val); - if (/^\d+$/.test(valStr)) { return valStr; } - return val; -}; - -var parseJsonArray = function(val) { - var arr = parseStringArray(val); - - if (!arr) { - return arr; - } - - return arr.map(function(el) { return JSON.parse(el); }); -}; - -var init = function(register) { - register(20, parseBigInteger); // int8 - register(21, parseInteger); // int2 - register(23, parseInteger); // int4 - register(26, parseInteger); // oid - register(700, parseFloat); // float4/real - register(701, parseFloat); // float8/double - register(16, parseBool); - register(1082, parseDate); // date - register(1114, parseDate); // timestamp without timezone - register(1184, parseDate); // timestamp - register(1005, parseIntegerArray); // _int2 - register(1007, parseIntegerArray); // _int4 - register(1016, parseBigIntegerArray); // _int8 - register(1021, parseFloatArray); // _float4 - register(1022, parseFloatArray); // _float8 - register(1231, parseFloatArray); // _numeric - register(1014, parseStringArray); //char - register(1015, parseStringArray); //varchar - register(1008, parseStringArray); - register(1009, parseStringArray); - register(1186, parseInterval); - register(17, parseByteA); - register(114, JSON.parse.bind(JSON)); - register(199, parseJsonArray); // json[] - register(2951, parseStringArray); // uuid[] -}; - -module.exports = { - init: init -}; diff --git a/package.json b/package.json index d97308756..81ee346b4 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,8 @@ "buffer-writer": "1.0.0", "pgpass": "0.0.1", "nan": "~0.6.0", - "packet-reader": "0.2.0" + "packet-reader": "0.2.0", + "pg-types": "1.0.0" }, "devDependencies": { "jshint": "1.1.0", diff --git a/test/integration/client/huge-numeric-tests.js b/test/integration/client/huge-numeric-tests.js index 4165711f7..8db3f2965 100644 --- a/test/integration/client/huge-numeric-tests.js +++ b/test/integration/client/huge-numeric-tests.js @@ -1,7 +1,7 @@ var helper = require(__dirname + '/test-helper'); helper.pg.connect(helper.config, assert.success(function(client, done) { - var types = require(__dirname + '/../../../lib/types'); + var types = require('pg-types'); //1231 = numericOID types.setTypeParser(1700, function(){ return 'yes'; diff --git a/test/unit/client/query-tests.js b/test/unit/client/query-tests.js deleted file mode 100644 index ab3672038..000000000 --- a/test/unit/client/query-tests.js +++ /dev/null @@ -1,74 +0,0 @@ -var helper = require(__dirname + '/test-helper'); -var q = {}; -q.dateParser = require(__dirname + "/../../../lib/types").getTypeParser(1114, 'text'); -q.stringArrayParser = require(__dirname + "/../../../lib/types").getTypeParser(1009, 'text'); - -test("testing dateParser", function() { - assert.equal(q.dateParser("2010-12-11 09:09:04").toString(),new Date("2010-12-11 09:09:04").toString()); -}); - -var testForMs = function(part, expected) { - var dateString = "2010-01-01 01:01:01" + part; - test('testing for correcting parsing of ' + dateString, function() { - var ms = q.dateParser(dateString).getMilliseconds(); - assert.equal(ms, expected) - }) -} - -testForMs('.1', 100); -testForMs('.01', 10); -testForMs('.74', 740); - -test("testing 2dateParser on dates without timezones", function() { - var actual = "2010-12-11 09:09:04.1"; - var expected = JSON.stringify(new Date(2010,11,11,9,9,4,100)) - assert.equal(JSON.stringify(q.dateParser(actual)),expected); -}); - -test("testing 2dateParser on dates with timezones", function() { - var actual = "2011-01-23 22:15:51.28-06"; - var expected = "\"2011-01-24T04:15:51.280Z\""; - assert.equal(JSON.stringify(q.dateParser(actual)),expected); -}); - -test("testing 2dateParser on dates with huge millisecond value", function() { - var actual = "2011-01-23 22:15:51.280843-06"; - var expected = "\"2011-01-24T04:15:51.280Z\""; - assert.equal(JSON.stringify(q.dateParser(actual)),expected); -}); - -test("testing empty array", function(){ - var input = '{}'; - var expected = []; - assert.deepEqual(q.stringArrayParser(input), expected); -}); - -test("testing empty string array", function(){ - var input = '{""}'; - var expected = [""]; - assert.deepEqual(q.stringArrayParser(input), expected); -}); - -test("testing numeric array", function(){ - var input = '{1,2,3,4}'; - var expected = [1,2,3,4]; - assert.deepEqual(q.stringArrayParser(input), expected); -}); - -test("testing stringy array", function(){ - var input = '{a,b,c,d}'; - var expected = ['a','b','c','d']; - assert.deepEqual(q.stringArrayParser(input), expected); -}); - -test("testing stringy array containing escaped strings", function(){ - var input = '{"\\"\\"\\"","\\\\\\\\\\\\"}'; - var expected = ['"""','\\\\\\']; - assert.deepEqual(q.stringArrayParser(input), expected); -}); - -test("testing NULL array", function(){ - var input = '{NULL,NULL}'; - var expected = [null,null]; - assert.deepEqual(q.stringArrayParser(input), expected); -}); diff --git a/test/unit/client/typed-query-results-tests.js b/test/unit/client/typed-query-results-tests.js deleted file mode 100644 index 35d807e3f..000000000 --- a/test/unit/client/typed-query-results-tests.js +++ /dev/null @@ -1,361 +0,0 @@ -var helper = require(__dirname + '/test-helper'); -//http://www.postgresql.org/docs/9.2/static/datatype.html -test('typed results', function() { - var client = helper.client(); - var con = client.connection; - con.emit('readyForQuery'); - var query = client.query("the bums lost"); - - - //TODO refactor to this style - var tests = [{ - name: 'string/varchar', - format: 'text', - dataTypeID: 1043, - actual: 'bang', - expected: 'bang' - },{ - name: 'integer/int4', - format: 'text', - dataTypeID: 23, - actual: '2147483647', - expected: 2147483647 - },{ - name: 'smallint/int2', - format: 'text', - dataTypeID: 21, - actual: '32767', - expected: 32767 - },{ - name: 'bigint/int8', - format: 'text', - dataTypeID: 20, - actual: '9223372036854775807', - expected: '9223372036854775807' - },{ - name: 'oid', - format: 'text', - dataTypeID: 26, - actual: '103', - expected: 103 - },{ - name: 'numeric', - format: 'text', - dataTypeID: 1700, - actual: '31415926535897932384626433832795028841971693993751058.16180339887498948482045868343656381177203091798057628', - expected: '31415926535897932384626433832795028841971693993751058.16180339887498948482045868343656381177203091798057628' - },{ - name: 'real/float4', - dataTypeID: 700, - format: 'text', - actual: '123.456', - expected: 123.456 - },{ - name: 'double precision / float8', - format: 'text', - dataTypeID: 701, - actual: '12345678.12345678', - expected: 12345678.12345678 - },{ - name: 'boolean true', - format: 'text', - dataTypeID: 16, - actual: 't', - expected: true - },{ - name: 'boolean false', - format: 'text', - dataTypeID: 16, - actual: 'f', - expected: false - },{ - name: 'boolean null', - format: 'text', - dataTypeID: 16, - actual: null, - expected: null - },{ - name: 'timestamptz with minutes in timezone', - format: 'text', - dataTypeID: 1184, - actual: '2010-10-31 14:54:13.74-05:30', - expected: function(val) { - assert.UTCDate(val, 2010, 9, 31, 20, 24, 13, 740); - } - }, { - name: 'timestamptz with other milisecond digits dropped', - format: 'text', - dataTypeID: 1184, - actual: '2011-01-23 22:05:00.68-06', - expected: function(val) { - assert.UTCDate(val, 2011, 0, 24, 4, 5, 00, 680); - } - }, { - name: 'timestampz with huge miliseconds in UTC', - format: 'text', - dataTypeID: 1184, - actual: '2010-10-30 14:11:12.730838Z', - expected: function(val) { - assert.UTCDate(val, 2010, 9, 30, 14, 11, 12, 730); - } - },{ - name: 'timestampz with no miliseconds', - format: 'text', - dataTypeID: 1184, - actual: '2010-10-30 13:10:01+05', - expected: function(val) { - assert.UTCDate(val, 2010, 9, 30, 8, 10, 01, 0); - } - },{ - name: 'timestamp', - format: 'text', - dataTypeID: 1114, - actual: '2010-10-31 00:00:00', - expected: function(val) { - assert.equal(val.toUTCString(), new Date(2010, 9, 31, 0, 0, 0, 0, 0).toUTCString()); - assert.equal(val.toString(), new Date(2010, 9, 31, 0, 0, 0, 0, 0, 0).toString()); - } - },{ - name: 'date', - format: 'text', - dataTypeID: 1082, - actual: '2010-10-31', - expected: function(val) { - var now = new Date(2010, 9, 31) - assert.UTCDate(val, 2010, now.getUTCMonth(), now.getUTCDate(), now.getUTCHours(), 0, 0, 0); - assert.equal(val.getHours(), now.getHours()) - } - },{ - name: 'interval time', - format: 'text', - dataTypeID: 1186, - actual: '01:02:03', - expected: function(val) { - assert.deepEqual(val, {'hours':1, 'minutes':2, 'seconds':3}) - } - },{ - name: 'interval long', - format: 'text', - dataTypeID: 1186, - actual: '1 year -32 days', - expected: function(val) { - assert.deepEqual(val, {'years':1, 'days':-32}) - } - },{ - name: 'interval combined negative', - format: 'text', - dataTypeID: 1186, - actual: '1 day -00:00:03', - expected: function(val) { - assert.deepEqual(val, {'days':1, 'seconds':-3}) - } - },{ - name: 'bytea', - format: 'text', - dataTypeID: 17, - actual: 'foo\\000\\200\\\\\\377', - expected: function(val) { - assert.deepEqual(val, new Buffer([102, 111, 111, 0, 128, 92, 255])); - } - },{ - name: 'empty bytea', - format: 'text', - dataTypeID: 17, - actual: '', - expected: function(val) { - assert.deepEqual(val, new Buffer(0)); - } - }, - - { - name : 'array/char', - format : 'text', - dataTypeID: 1014, - actual: '{asdf,asdf}', - expected : function(val){ - assert.deepEqual(val, ['asdf','asdf']); - } - },{ - name : 'array/varchar', - format : 'text', - dataTypeID: 1015, - actual: '{asdf,asdf}', - expected :function(val){ - assert.deepEqual(val, ['asdf','asdf']); - } - },{ - name : 'array/text', - format : 'text', - dataTypeID: 1008, - actual: '{"hello world"}', - expected :function(val){ - assert.deepEqual(val, ['hello world']); - } - },{ - name : 'array/numeric', - format : 'text', - dataTypeID: 1231, - actual: '{1.2,3.4}', - expected :function(val){ - assert.deepEqual(val, [1.2,3.4]); - } - },{ - name : 'array/int2', - format : 'text', - dataTypeID: 1005, - actual: '{-32768, -32767, 32766, 32767}', - expected :function(val){ - assert.deepEqual(val, [-32768, -32767, 32766, 32767]); - } - },{ - name : 'array/int4', - format : 'text', - dataTypeID: 1007, - actual: '{-2147483648, -2147483647, 2147483646, 2147483647}', - expected :function(val){ - assert.deepEqual(val, [-2147483648, -2147483647, 2147483646, 2147483647]); - } - },{ - name : 'array/int8', - format : 'text', - dataTypeID: 1016, - actual: '{-9223372036854775808, -9223372036854775807, 9223372036854775806, 9223372036854775807}', - expected :function(val){ - assert.deepEqual(val, [ - '-9223372036854775808', - '-9223372036854775807', - '9223372036854775806', - '9223372036854775807' - ]); - } - },{ - name : 'array/float4', - format : 'text', - dataTypeID: 1021, - actual: '{1.2, 3.4}', - expected :function(val){ - assert.deepEqual(val, [1.2, 3.4]); - } - },{ - name : 'array/float8', - format : 'text', - dataTypeID: 1022, - actual: '{-12345678.1234567, 12345678.12345678}', - expected :function(val){ - assert.deepEqual(val, [-12345678.1234567, 12345678.12345678]); - } - }, - - { - name: 'binary-string/varchar', - format: 'binary', - dataTypeID: 1043, - actual: 'bang', - expected: 'bang' - },{ - name: 'binary-integer/int4', - format: 'binary', - dataTypeID: 23, - actual: [0, 0, 0, 100], - expected: 100 - },{ - name: 'binary-smallint/int2', - format: 'binary', - dataTypeID: 21, - actual: [0, 101], - expected: 101 - },{ -// name: 'binary-bigint/int8', -// format: 'binary', -// dataTypeID: 20, -// actual: [0, 0, 0, 0, 0, 0, 0, 102], -// expected: '102' -// },{ -// name: 'binary-bigint/int8-full', -// format: 'binary', -// dataTypeID: 20, -// actual: [1, 0, 0, 0, 0, 0, 0, 102], -// expected: '72057594037928038' -// },{ - name: 'binary-oid', - format: 'binary', - dataTypeID: 26, - actual: [0, 0, 0, 103], - expected: 103 - },{ - name: 'binary-numeric', - format: 'binary', - dataTypeID: 1700, - actual: [0,2,0,0,0,0,0,0x64,0,12,0xd,0x48,0,0,0,0], - expected: 12.34 - },{ - name: 'binary-real/float4', - dataTypeID: 700, - format: 'binary', - actual: [0x41, 0x48, 0x00, 0x00], - expected: 12.5 - },{ - name: 'binary-double precision / float8', - format: 'binary', - dataTypeID: 701, - actual: [0x3F,0xF3,0x33,0x33,0x33,0x33,0x33,0x33], - expected: 1.2 - },{ - name: 'binary-boolean true', - format: 'binary', - dataTypeID: 16, - actual: [1], - expected: true - },{ - name: 'binary-boolean false', - format: 'binary', - dataTypeID: 16, - actual: [0], - expected: false - },{ - name: 'binary-boolean null', - format: 'binary', - dataTypeID: 16, - actual: null, - expected: null - },{ - name: 'binary-timestamp', - format: 'binary', - dataTypeID: 1184, - actual: [0x00, 0x01, 0x36, 0xee, 0x3e, 0x66, 0x9f, 0xe0], - expected: function(val) { - assert.UTCDate(val, 2010, 9, 31, 20, 24, 13, 740); - } - },{ - name: 'binary-string', - format: 'binary', - dataTypeID: 25, - actual: new Buffer([0x73, 0x6c, 0x61, 0x64, 0x64, 0x61]), - expected: 'sladda' - }]; - - - con.emit('rowDescription', { - fieldCount: tests.length, - fields: tests - }); - - assert.emits(query, 'row', function(row) { - for(var i = 0; i < tests.length; i++) { - test('parses ' + tests[i].name, function() { - var expected = tests[i].expected; - if(typeof expected === 'function') { - return expected(row[tests[i].name]); - } - assert.strictEqual(row[tests[i].name], expected); - }); - } - }); - - assert.ok(con.emit('dataRow', { - fields: tests.map(function(x) { - return x.actual; - }) - })); - -}); diff --git a/test/unit/utils-tests.js b/test/unit/utils-tests.js index 30ff9d28c..56c81dc52 100644 --- a/test/unit/utils-tests.js +++ b/test/unit/utils-tests.js @@ -2,6 +2,14 @@ require(__dirname + '/test-helper'); var utils = require(__dirname + "/../../lib/utils"); var defaults = require(__dirname + "/../../lib").defaults; + +test('ensure types is exported on root object', function() { + var pg = require('../../lib') + assert(pg.types) + assert(pg.types.getTypeParser) + assert(pg.types.setTypeParser) +}) + //this tests the monkey patching //to ensure comptability with older //versions of node @@ -21,27 +29,22 @@ test("EventEmitter.once", function(t) { }); -test('types are exported', function() { - var pg = require(__dirname + '/../../lib/index'); - assert.ok(pg.types); -}); - test('normalizing query configs', function() { var config - var callback = function () {} + var callback = function () {} config = utils.normalizeQueryConfig({text: 'TEXT'}) - assert.same(config, {text: 'TEXT'}) + assert.same(config, {text: 'TEXT'}) - config = utils.normalizeQueryConfig({text: 'TEXT'}, [10]) - assert.deepEqual(config, {text: 'TEXT', values: [10]}) + config = utils.normalizeQueryConfig({text: 'TEXT'}, [10]) + assert.deepEqual(config, {text: 'TEXT', values: [10]}) - config = utils.normalizeQueryConfig({text: 'TEXT', values: [10]}) - assert.deepEqual(config, {text: 'TEXT', values: [10]}) + config = utils.normalizeQueryConfig({text: 'TEXT', values: [10]}) + assert.deepEqual(config, {text: 'TEXT', values: [10]}) - config = utils.normalizeQueryConfig('TEXT', [10], callback) - assert.deepEqual(config, {text: 'TEXT', values: [10], callback: callback}) + config = utils.normalizeQueryConfig('TEXT', [10], callback) + assert.deepEqual(config, {text: 'TEXT', values: [10], callback: callback}) - config = utils.normalizeQueryConfig({text: 'TEXT', values: [10]}, callback) - assert.deepEqual(config, {text: 'TEXT', values: [10], callback: callback}) + config = utils.normalizeQueryConfig({text: 'TEXT', values: [10]}, callback) + assert.deepEqual(config, {text: 'TEXT', values: [10], callback: callback}) })