mirror of
https://github.com/brianc/node-postgres.git
synced 2025-12-08 20:16:25 +00:00
Break type parsing into separate module
This commit is contained in:
parent
e8e16f866f
commit
876abe8730
@ -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; });
|
||||
});
|
||||
|
||||
@ -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,7 +11,6 @@ var PG = function(clientConstructor) {
|
||||
this.Client = pool.Client = clientConstructor;
|
||||
this.Query = this.Client.Query;
|
||||
this.pools = pool;
|
||||
this.types = types;
|
||||
this.Connection = Connection;
|
||||
};
|
||||
|
||||
|
||||
@ -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');
|
||||
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
}
|
||||
};
|
||||
@ -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
|
||||
};
|
||||
@ -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
|
||||
};
|
||||
@ -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
|
||||
};
|
||||
@ -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",
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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);
|
||||
});
|
||||
@ -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;
|
||||
})
|
||||
}));
|
||||
|
||||
});
|
||||
@ -21,27 +21,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})
|
||||
})
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user