Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 92 additions & 0 deletions lib/arrayParser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
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(char) {
return this.recorded.push(char);
};
ArrayParser.prototype.newEntry = function(includeEmpty) {
var entry;
if (this.recorded.length > 0 || includeEmpty) {
entry = this.recorded.join("");
if (entry === "NULL") {
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);
}
}
30 changes: 15 additions & 15 deletions lib/textParsers.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
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
Expand Down Expand Up @@ -51,24 +53,22 @@ var parseBool = function(val) {
}

var parseIntegerArray = function(val) {
return JSON.parse(val.replace("{","[").replace("}","]"));
if(!val) return null;
var p = arrayParser.create(val, function(entry){
if(entry != null)
entry = parseInt(entry);

return entry;
});

return p.parse();
};

var parseStringArray = function(val) {
if (!val) return null;
if (val[0] !== '{' || val[val.length-1] !== '}')
throw "Not postgresql array! (" + arrStr + ")";

var x = val.substring(1, val.length - 1);
if (x === '') return [];
x = x.match(/(NULL|[^,]+|"((?:.|\n|\r)*?)(?!\\)"|\{((?:.|\n|\r)*?(?!\\)\}) (,|$))/mg);
if (x === null) throw "Not postgre array";
return x.map(function (el) {
if (el === 'NULL') return null;
if (el[0] === '{') return arguments.callee(el);
if (el[0] === '\"') return el.substring(1, el.length - 1).replace(/\\(.)/g, '$1');
return el;
});
if(!val) return null;

var p = arrayParser.create(val);
return p.parse();
};


Expand Down
95 changes: 95 additions & 0 deletions test/integration/client/array-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,101 @@ test('parsing array results', function() {
pg.end();
}))
})

test('empty array', function(){
client.query("SELECT '{}'::text[] as names", assert.success(function(result) {
var names = result.rows[0].names;
assert.lengthIs(names, 0);
pg.end();
}))
})

test('element containing comma', function(){
client.query("SELECT '{\"joe,bob\",jim}'::text[] as names", assert.success(function(result) {
var names = result.rows[0].names;
assert.lengthIs(names, 2);
assert.equal(names[0], 'joe,bob');
assert.equal(names[1], 'jim');
pg.end();
}))
})

test('bracket in quotes', function(){
client.query("SELECT '{\"{\",\"}\"}'::text[] as names", assert.success(function(result) {
var names = result.rows[0].names;
assert.lengthIs(names, 2);
assert.equal(names[0], '{');
assert.equal(names[1], '}');
pg.end();
}))
})

test('null value', function(){
client.query("SELECT '{joe,null,bob}'::text[] as names", assert.success(function(result) {
var names = result.rows[0].names;
assert.lengthIs(names, 3);
assert.equal(names[0], 'joe');
assert.equal(names[1], null);
assert.equal(names[2], 'bob');
pg.end();
}))
})

test('element containing quote char', function(){
client.query("SELECT '{\"joe''\",jim'',\"bob\\\\\"\"}'::text[] as names", assert.success(function(result) {
var names = result.rows[0].names;
assert.lengthIs(names, 3);
assert.equal(names[0], 'joe\'');
assert.equal(names[1], 'jim\'');
assert.equal(names[2], 'bob"');
pg.end();
}))
})

test('nested array', function(){
client.query("SELECT '{{1,joe},{2,bob}}'::text[] as names", assert.success(function(result) {
var names = result.rows[0].names;
assert.lengthIs(names, 2);

assert.lengthIs(names[0], 2);
assert.equal(names[0][0], '1');
assert.equal(names[0][1], 'joe');

assert.lengthIs(names[1], 2);
assert.equal(names[1][0], '2');
assert.equal(names[1][1], 'bob');

pg.end();
}))
})

test('integer array', function(){
client.query("SELECT '{1,2,3}'::integer[] as names", assert.success(function(result) {
var names = result.rows[0].names;
assert.lengthIs(names, 3);
assert.equal(names[0], 1);
assert.equal(names[1], 2);
assert.equal(names[2], 3);
pg.end();
}))
})

test('integer nested array', function(){
client.query("SELECT '{{1,100},{2,100},{3,100}}'::integer[] as names", assert.success(function(result) {
var names = result.rows[0].names;
assert.lengthIs(names, 3);
assert.equal(names[0][0], 1);
assert.equal(names[0][1], 100);

assert.equal(names[1][0], 2);
assert.equal(names[1][1], 100);

assert.equal(names[2][0], 3);
assert.equal(names[2][1], 100);
pg.end();
}))
})

}))
})

Expand Down