Skip to content

Commit 9389a04

Browse files
author
Sandro Santilli
committed
Add warnings and notices to JSON response. Closes #104.
1 parent 493955a commit 9389a04

File tree

6 files changed

+143
-2
lines changed

6 files changed

+143
-2
lines changed

NEWS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* CartoDB redis interaction delegated to "cartodb-redis" module
44
* Optionally read user-specific database_host and database_password
55
from redis, as per CartoDB-2.5.0 model (#120, #121)
6+
* Add warnings and notices to JSON response (#104)
67

78
1.6.3 - 2013-11-10
89
------------------

app/models/formats/json.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,14 @@ p.transform = function(result, options, callback) {
8282
total_rows: result.rowCount,
8383
rows: result.rows
8484
}
85+
if ( result.notices ) {
86+
for (var i=0; i<result.notices.length; ++i) {
87+
var m = result.notices[i];
88+
var l = m.severity.toLowerCase() + 's';
89+
if ( ! j[l] ) j[l] = [];
90+
j[l].push(m.message);
91+
}
92+
}
8593
callback(null, j);
8694
};
8795

app/models/formats/pg.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,14 @@ pg.prototype.handleQueryRow = function(row, result) {
3131
result.addRow(row);
3232
};
3333

34+
pg.prototype.handleNotice = function(msg, result) {
35+
if ( ! result.notices ) result.notices = [];
36+
for (var i=0; i<msg.length; ++i) {
37+
var m = msg[i];
38+
result.notices.push(m);
39+
}
40+
};
41+
3442
pg.prototype.handleQueryEnd = function(result) {
3543
if ( this.error ) {
3644
this.callback(this.error);
@@ -104,6 +112,9 @@ pg.prototype.sendResponse = function(opts, callback) {
104112
query.on('row', that.handleQueryRow.bind(that));
105113
query.on('end', that.handleQueryEnd.bind(that));
106114
query.on('error', function(err) { that.error = err; });
115+
query.on('notice', function(msg) {
116+
that.handleNotice(msg, query._result);
117+
});
107118
});
108119
};
109120

app/models/psql.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,10 +179,20 @@ var PSQL = function(dbopts) {
179179
function(err, client, done){
180180
if (err) throw err;
181181
var query = client.query(sql);
182+
183+
// forward notices to query
184+
var noticeListener = function() {
185+
query.emit('notice', arguments);
186+
};
187+
client.on('notice', noticeListener);
188+
182189
// NOTE: for some obscure reason passing "done" directly
183190
// as the listener works but can be slower
184191
// (by x2 factor!)
185-
query.on('end', function() { done(); });
192+
query.on('end', function() {
193+
client.removeListener('notice', noticeListener);
194+
done();
195+
});
186196
return query;
187197
},
188198
function(err, query){

doc/API.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,9 @@ The JSON response is as follows:
6363
updated_at: "2012-02-12T21:34:08.193Z",
6464
valid: true
6565
}
66-
]
66+
],
67+
notices: [ 'notice1', 'notice2' ], // optional
68+
warnings: [ 'warning1', 'warning2' ] // optional
6769
}
6870
```
6971

test/acceptance/app.test.js

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1116,6 +1116,115 @@ test('timezone info in JSON output', function(done){
11161116
);
11171117
});
11181118

1119+
// WARNING and NOTICE in JSON output
1120+
// See https://github.com/CartoDB/CartoDB-SQL-API/issues/104
1121+
test('notice and warning info in JSON output', function(done){
1122+
Step(
1123+
function addRaiseFunction() {
1124+
var next = this;
1125+
assert.response(app, {
1126+
url: '/api/v1/sql?' + querystring.stringify({
1127+
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;",
1128+
api_key: '1234'
1129+
}),
1130+
headers: {host: 'vizzuality.cartodb.com'},
1131+
method: 'GET'
1132+
},{ }, function(res) {
1133+
var err = null;
1134+
try {
1135+
assert.equal(res.statusCode, 200, res.statusCode + ': ' + res.body);
1136+
} catch (e) { err = e; }
1137+
next(err);
1138+
});
1139+
},
1140+
function raiseNotice(err) {
1141+
if ( err ) throw err;
1142+
var next = this;
1143+
assert.response(app, {
1144+
url: '/api/v1/sql?' + querystring.stringify({
1145+
q: "select raise('notice', 'hello notice')"
1146+
}),
1147+
headers: {host: 'vizzuality.cartodb.com'},
1148+
method: 'GET'
1149+
},{}, function(res) {
1150+
var err = null;
1151+
try {
1152+
assert.equal(res.statusCode, 200, res.body);
1153+
var parsedBody = JSON.parse(res.body);
1154+
assert.ok(parsedBody.hasOwnProperty('notices'), 'Missing notices from result');
1155+
assert.equal(parsedBody.notices.length, 1);
1156+
assert.equal(parsedBody.notices[0], 'hello notice');
1157+
} catch (e) { err = e; }
1158+
next(err);
1159+
});
1160+
},
1161+
function raiseWarning(err) {
1162+
if ( err ) throw err;
1163+
var next = this;
1164+
assert.response(app, {
1165+
url: '/api/v1/sql?' + querystring.stringify({
1166+
q: "select raise('warning', 'hello warning')"
1167+
}),
1168+
headers: {host: 'vizzuality.cartodb.com'},
1169+
method: 'GET'
1170+
},{}, function(res) {
1171+
var err = null;
1172+
try {
1173+
assert.equal(res.statusCode, 200, res.body);
1174+
var parsedBody = JSON.parse(res.body);
1175+
assert.ok(parsedBody.hasOwnProperty('warnings'), 'Missing warnings from result');
1176+
assert.equal(parsedBody.warnings.length, 1);
1177+
assert.equal(parsedBody.warnings[0], 'hello warning');
1178+
} catch (e) { err = e; }
1179+
next(err);
1180+
});
1181+
},
1182+
function raiseBothWarningAndNotice(err) {
1183+
if ( err ) throw err;
1184+
var next = this;
1185+
assert.response(app, {
1186+
url: '/api/v1/sql?' + querystring.stringify({
1187+
q: "select raise('warning', 'hello again warning'), raise('notice', 'hello again notice');"
1188+
}),
1189+
headers: {host: 'vizzuality.cartodb.com'},
1190+
method: 'GET'
1191+
},{}, function(res) {
1192+
var err = null;
1193+
try {
1194+
assert.equal(res.statusCode, 200, res.body);
1195+
var parsedBody = JSON.parse(res.body);
1196+
assert.ok(parsedBody.hasOwnProperty('warnings'), 'Missing warnings from result');
1197+
assert.equal(parsedBody.warnings.length, 1);
1198+
assert.equal(parsedBody.warnings[0], 'hello again warning');
1199+
assert.ok(parsedBody.hasOwnProperty('notices'), 'Missing notices from result');
1200+
assert.equal(parsedBody.notices.length, 1);
1201+
assert.equal(parsedBody.notices[0], 'hello again notice');
1202+
} catch (e) { err = e; }
1203+
next(err);
1204+
});
1205+
},
1206+
function delRaiseFunction(err) {
1207+
var next = this;
1208+
assert.response(app, {
1209+
url: '/api/v1/sql?' + querystring.stringify({
1210+
q: "DROP function raise(text, text)",
1211+
api_key: '1234'
1212+
}),
1213+
headers: {host: 'vizzuality.cartodb.com'},
1214+
method: 'GET'
1215+
},{ }, function(res) {
1216+
try {
1217+
assert.equal(res.statusCode, 200, res.body);
1218+
var parsedBody = JSON.parse(res.body);
1219+
} catch (e) { err = new Error(err + ',' + e); }
1220+
next(err);
1221+
});
1222+
},
1223+
function finish(err) {
1224+
done(err);
1225+
}
1226+
);
1227+
});
11191228

11201229
/**
11211230
* CORS

0 commit comments

Comments
 (0)