Add warnings and notices to JSON response. Closes #104.

This commit is contained in:
Sandro Santilli 2013-11-18 17:01:06 +01:00
parent 493955a468
commit 9389a04030
6 changed files with 143 additions and 2 deletions

View File

@ -3,6 +3,7 @@
* CartoDB redis interaction delegated to "cartodb-redis" module * CartoDB redis interaction delegated to "cartodb-redis" module
* Optionally read user-specific database_host and database_password * Optionally read user-specific database_host and database_password
from redis, as per CartoDB-2.5.0 model (#120, #121) from redis, as per CartoDB-2.5.0 model (#120, #121)
* Add warnings and notices to JSON response (#104)
1.6.3 - 2013-11-10 1.6.3 - 2013-11-10
------------------ ------------------

View File

@ -82,6 +82,14 @@ p.transform = function(result, options, callback) {
total_rows: result.rowCount, total_rows: result.rowCount,
rows: result.rows rows: result.rows
} }
if ( result.notices ) {
for (var i=0; i<result.notices.length; ++i) {
var m = result.notices[i];
var l = m.severity.toLowerCase() + 's';
if ( ! j[l] ) j[l] = [];
j[l].push(m.message);
}
}
callback(null, j); callback(null, j);
}; };

View File

@ -31,6 +31,14 @@ pg.prototype.handleQueryRow = function(row, result) {
result.addRow(row); result.addRow(row);
}; };
pg.prototype.handleNotice = function(msg, result) {
if ( ! result.notices ) result.notices = [];
for (var i=0; i<msg.length; ++i) {
var m = msg[i];
result.notices.push(m);
}
};
pg.prototype.handleQueryEnd = function(result) { pg.prototype.handleQueryEnd = function(result) {
if ( this.error ) { if ( this.error ) {
this.callback(this.error); this.callback(this.error);
@ -104,6 +112,9 @@ pg.prototype.sendResponse = function(opts, callback) {
query.on('row', that.handleQueryRow.bind(that)); query.on('row', that.handleQueryRow.bind(that));
query.on('end', that.handleQueryEnd.bind(that)); query.on('end', that.handleQueryEnd.bind(that));
query.on('error', function(err) { that.error = err; }); query.on('error', function(err) { that.error = err; });
query.on('notice', function(msg) {
that.handleNotice(msg, query._result);
});
}); });
}; };

View File

@ -179,10 +179,20 @@ var PSQL = function(dbopts) {
function(err, client, done){ function(err, client, done){
if (err) throw err; if (err) throw err;
var query = client.query(sql); var query = client.query(sql);
// forward notices to query
var noticeListener = function() {
query.emit('notice', arguments);
};
client.on('notice', noticeListener);
// NOTE: for some obscure reason passing "done" directly // NOTE: for some obscure reason passing "done" directly
// as the listener works but can be slower // as the listener works but can be slower
// (by x2 factor!) // (by x2 factor!)
query.on('end', function() { done(); }); query.on('end', function() {
client.removeListener('notice', noticeListener);
done();
});
return query; return query;
}, },
function(err, query){ function(err, query){

View File

@ -63,7 +63,9 @@ The JSON response is as follows:
updated_at: "2012-02-12T21:34:08.193Z", updated_at: "2012-02-12T21:34:08.193Z",
valid: true valid: true
} }
] ],
notices: [ 'notice1', 'notice2' ], // optional
warnings: [ 'warning1', 'warning2' ] // optional
} }
``` ```

View File

@ -1116,6 +1116,115 @@ test('timezone info in JSON output', function(done){
); );
}); });
// WARNING and NOTICE in JSON output
// See https://github.com/CartoDB/CartoDB-SQL-API/issues/104
test('notice and warning info in JSON output', function(done){
Step(
function addRaiseFunction() {
var next = this;
assert.response(app, {
url: '/api/v1/sql?' + querystring.stringify({
q: "create or replace function raise(lvl text, msg text) returns void as $$ begin if lvl = 'notice' then raise notice '%', msg; elsif lvl = 'warning' then raise warning '%', msg; else raise exception '%', msg; end if; end; $$ language plpgsql;",
api_key: '1234'
}),
headers: {host: 'vizzuality.cartodb.com'},
method: 'GET'
},{ }, function(res) {
var err = null;
try {
assert.equal(res.statusCode, 200, res.statusCode + ': ' + res.body);
} catch (e) { err = e; }
next(err);
});
},
function raiseNotice(err) {
if ( err ) throw err;
var next = this;
assert.response(app, {
url: '/api/v1/sql?' + querystring.stringify({
q: "select raise('notice', 'hello notice')"
}),
headers: {host: 'vizzuality.cartodb.com'},
method: 'GET'
},{}, function(res) {
var err = null;
try {
assert.equal(res.statusCode, 200, res.body);
var parsedBody = JSON.parse(res.body);
assert.ok(parsedBody.hasOwnProperty('notices'), 'Missing notices from result');
assert.equal(parsedBody.notices.length, 1);
assert.equal(parsedBody.notices[0], 'hello notice');
} catch (e) { err = e; }
next(err);
});
},
function raiseWarning(err) {
if ( err ) throw err;
var next = this;
assert.response(app, {
url: '/api/v1/sql?' + querystring.stringify({
q: "select raise('warning', 'hello warning')"
}),
headers: {host: 'vizzuality.cartodb.com'},
method: 'GET'
},{}, function(res) {
var err = null;
try {
assert.equal(res.statusCode, 200, res.body);
var parsedBody = JSON.parse(res.body);
assert.ok(parsedBody.hasOwnProperty('warnings'), 'Missing warnings from result');
assert.equal(parsedBody.warnings.length, 1);
assert.equal(parsedBody.warnings[0], 'hello warning');
} catch (e) { err = e; }
next(err);
});
},
function raiseBothWarningAndNotice(err) {
if ( err ) throw err;
var next = this;
assert.response(app, {
url: '/api/v1/sql?' + querystring.stringify({
q: "select raise('warning', 'hello again warning'), raise('notice', 'hello again notice');"
}),
headers: {host: 'vizzuality.cartodb.com'},
method: 'GET'
},{}, function(res) {
var err = null;
try {
assert.equal(res.statusCode, 200, res.body);
var parsedBody = JSON.parse(res.body);
assert.ok(parsedBody.hasOwnProperty('warnings'), 'Missing warnings from result');
assert.equal(parsedBody.warnings.length, 1);
assert.equal(parsedBody.warnings[0], 'hello again warning');
assert.ok(parsedBody.hasOwnProperty('notices'), 'Missing notices from result');
assert.equal(parsedBody.notices.length, 1);
assert.equal(parsedBody.notices[0], 'hello again notice');
} catch (e) { err = e; }
next(err);
});
},
function delRaiseFunction(err) {
var next = this;
assert.response(app, {
url: '/api/v1/sql?' + querystring.stringify({
q: "DROP function raise(text, text)",
api_key: '1234'
}),
headers: {host: 'vizzuality.cartodb.com'},
method: 'GET'
},{ }, function(res) {
try {
assert.equal(res.statusCode, 200, res.body);
var parsedBody = JSON.parse(res.body);
} catch (e) { err = new Error(err + ',' + e); }
next(err);
});
},
function finish(err) {
done(err);
}
);
});
/** /**
* CORS * CORS