Fossil SCM

Added /json/tag/find.

stephan 2011-10-06 23:12 UTC json-multitag-test
Commit 9d27ade314cabed175c5af1c799751290f7c6fbf
2 files changed +34 -11 +120 -1
+34 -11
--- src/json.c
+++ src/json.c
@@ -821,11 +821,11 @@
821821
**
822822
** FIXME: if msg is NULL then use a standard string for
823823
** the given code. If !*msg then elide the "text" property,
824824
** for consistency with how json_err() works.
825825
*/
826
-void json_warn( int code, char const * msg ){
826
+void json_warn( int code, char const * fmt, ... ){
827827
cson_value * objV = NULL;
828828
cson_object * obj = NULL;
829829
assert( (code>FSL_JSON_W_START)
830830
&& (code<FSL_JSON_W_END)
831831
&& "Invalid warning code.");
@@ -838,15 +838,20 @@
838838
objV = cson_value_new_object();
839839
assert((NULL != objV) && "Alloc error.");
840840
cson_array_append(g.json.warnings.a, objV);
841841
obj = cson_value_get_object(objV);
842842
cson_object_set(obj,"code",cson_value_new_integer(code));
843
- if(msg && *msg){
844
- /* FIXME: treat NULL msg as standard warning message for
843
+ if(fmt && *fmt){
844
+ /* FIXME: treat NULL fmt as standard warning message for
845845
the code, but we don't have those yet.
846846
*/
847
- cson_object_set(obj,"text",cson_value_new_string(msg,strlen(msg)));
847
+ va_list vargs;
848
+ va_start(vargs,fmt);
849
+ char * msg = vmprintf(fmt,vargs);
850
+ va_end(vargs);
851
+ cson_object_set(obj,"text", cson_value_new_string(msg,strlen(msg)));
852
+ free(msg);
848853
}
849854
}
850855
851856
/*
852857
** Splits zStr (which must not be NULL) into tokens separated by the
@@ -1261,11 +1266,11 @@
12611266
** Epoch timestamp. Requires the db, so this cannot be used before the
12621267
** repo is opened (will trigger a fatal error in db_xxx()).
12631268
*/
12641269
cson_value * json_julian_to_timestamp(double j){
12651270
return cson_value_new_integer((cson_int_t)
1266
- db_int64(0,"SELECT strftime('%%s',%lf)",j)
1271
+ db_int64(0,"SELECT cast(strftime('%%s',%lf) as int)",j)
12671272
);
12681273
}
12691274
12701275
/*
12711276
** Returns a timestamp value.
@@ -1525,25 +1530,43 @@
15251530
** Iterates through a prepared SELECT statement and converts each row
15261531
** to a JSON object. If pTgt is not NULL then it must be-a Array
15271532
** object and this function will return pTgt. If pTgt is NULL then a
15281533
** new Array object is created and returned (owned by the
15291534
** caller). Each row of pStmt is converted to an Object and appended
1530
-** to the array.
1535
+** to the array. If the result set has no rows AND pTgt is NULL then
1536
+** NULL is returned.
15311537
*/
15321538
cson_value * json_stmt_to_array_of_obj(Stmt *pStmt,
15331539
cson_value * pTgt){
1534
- cson_value * v = pTgt ? pTgt : cson_value_new_array();
1535
- cson_array * a = cson_value_get_array(pTgt ? pTgt : v);
1540
+ cson_value * v = pTgt;
1541
+ cson_array * a = NULL;
15361542
char const * warnMsg = NULL;
1537
- assert( NULL != a );
1543
+ if(v && !cson_value_is_array(v)){
1544
+ return NULL;
1545
+ }
15381546
while( (SQLITE_ROW==db_step(pStmt)) ){
1539
- cson_value * row = cson_sqlite3_row_to_object(pStmt->pStmt);
1547
+ cson_value * row = NULL;
1548
+ if(!a){
1549
+ if(!v){
1550
+ v = cson_value_new_array();
1551
+ }
1552
+ a = cson_value_get_array(v);
1553
+ assert(NULL!=a);
1554
+ }
1555
+ row = cson_sqlite3_row_to_object(pStmt->pStmt);
15401556
if(!row && !warnMsg){
15411557
warnMsg = "Could not convert at least one result row to JSON.";
15421558
continue;
15431559
}
1544
- cson_array_append(a, row);
1560
+ if( 0 != cson_array_append(a, row) ){
1561
+ cson_value_free(row);
1562
+ assert( 0 && "Alloc error.");
1563
+ if(pTgt != v) {
1564
+ cson_value_free(v);
1565
+ }
1566
+ return NULL;
1567
+ }
15451568
}
15461569
if(warnMsg){
15471570
json_warn( FSL_JSON_W_ROW_TO_JSON_FAILED, warnMsg );
15481571
}
15491572
return v;
15501573
--- src/json.c
+++ src/json.c
@@ -821,11 +821,11 @@
821 **
822 ** FIXME: if msg is NULL then use a standard string for
823 ** the given code. If !*msg then elide the "text" property,
824 ** for consistency with how json_err() works.
825 */
826 void json_warn( int code, char const * msg ){
827 cson_value * objV = NULL;
828 cson_object * obj = NULL;
829 assert( (code>FSL_JSON_W_START)
830 && (code<FSL_JSON_W_END)
831 && "Invalid warning code.");
@@ -838,15 +838,20 @@
838 objV = cson_value_new_object();
839 assert((NULL != objV) && "Alloc error.");
840 cson_array_append(g.json.warnings.a, objV);
841 obj = cson_value_get_object(objV);
842 cson_object_set(obj,"code",cson_value_new_integer(code));
843 if(msg && *msg){
844 /* FIXME: treat NULL msg as standard warning message for
845 the code, but we don't have those yet.
846 */
847 cson_object_set(obj,"text",cson_value_new_string(msg,strlen(msg)));
 
 
 
 
 
848 }
849 }
850
851 /*
852 ** Splits zStr (which must not be NULL) into tokens separated by the
@@ -1261,11 +1266,11 @@
1261 ** Epoch timestamp. Requires the db, so this cannot be used before the
1262 ** repo is opened (will trigger a fatal error in db_xxx()).
1263 */
1264 cson_value * json_julian_to_timestamp(double j){
1265 return cson_value_new_integer((cson_int_t)
1266 db_int64(0,"SELECT strftime('%%s',%lf)",j)
1267 );
1268 }
1269
1270 /*
1271 ** Returns a timestamp value.
@@ -1525,25 +1530,43 @@
1525 ** Iterates through a prepared SELECT statement and converts each row
1526 ** to a JSON object. If pTgt is not NULL then it must be-a Array
1527 ** object and this function will return pTgt. If pTgt is NULL then a
1528 ** new Array object is created and returned (owned by the
1529 ** caller). Each row of pStmt is converted to an Object and appended
1530 ** to the array.
 
1531 */
1532 cson_value * json_stmt_to_array_of_obj(Stmt *pStmt,
1533 cson_value * pTgt){
1534 cson_value * v = pTgt ? pTgt : cson_value_new_array();
1535 cson_array * a = cson_value_get_array(pTgt ? pTgt : v);
1536 char const * warnMsg = NULL;
1537 assert( NULL != a );
 
 
1538 while( (SQLITE_ROW==db_step(pStmt)) ){
1539 cson_value * row = cson_sqlite3_row_to_object(pStmt->pStmt);
 
 
 
 
 
 
 
 
1540 if(!row && !warnMsg){
1541 warnMsg = "Could not convert at least one result row to JSON.";
1542 continue;
1543 }
1544 cson_array_append(a, row);
 
 
 
 
 
 
 
1545 }
1546 if(warnMsg){
1547 json_warn( FSL_JSON_W_ROW_TO_JSON_FAILED, warnMsg );
1548 }
1549 return v;
1550
--- src/json.c
+++ src/json.c
@@ -821,11 +821,11 @@
821 **
822 ** FIXME: if msg is NULL then use a standard string for
823 ** the given code. If !*msg then elide the "text" property,
824 ** for consistency with how json_err() works.
825 */
826 void json_warn( int code, char const * fmt, ... ){
827 cson_value * objV = NULL;
828 cson_object * obj = NULL;
829 assert( (code>FSL_JSON_W_START)
830 && (code<FSL_JSON_W_END)
831 && "Invalid warning code.");
@@ -838,15 +838,20 @@
838 objV = cson_value_new_object();
839 assert((NULL != objV) && "Alloc error.");
840 cson_array_append(g.json.warnings.a, objV);
841 obj = cson_value_get_object(objV);
842 cson_object_set(obj,"code",cson_value_new_integer(code));
843 if(fmt && *fmt){
844 /* FIXME: treat NULL fmt as standard warning message for
845 the code, but we don't have those yet.
846 */
847 va_list vargs;
848 va_start(vargs,fmt);
849 char * msg = vmprintf(fmt,vargs);
850 va_end(vargs);
851 cson_object_set(obj,"text", cson_value_new_string(msg,strlen(msg)));
852 free(msg);
853 }
854 }
855
856 /*
857 ** Splits zStr (which must not be NULL) into tokens separated by the
@@ -1261,11 +1266,11 @@
1266 ** Epoch timestamp. Requires the db, so this cannot be used before the
1267 ** repo is opened (will trigger a fatal error in db_xxx()).
1268 */
1269 cson_value * json_julian_to_timestamp(double j){
1270 return cson_value_new_integer((cson_int_t)
1271 db_int64(0,"SELECT cast(strftime('%%s',%lf) as int)",j)
1272 );
1273 }
1274
1275 /*
1276 ** Returns a timestamp value.
@@ -1525,25 +1530,43 @@
1530 ** Iterates through a prepared SELECT statement and converts each row
1531 ** to a JSON object. If pTgt is not NULL then it must be-a Array
1532 ** object and this function will return pTgt. If pTgt is NULL then a
1533 ** new Array object is created and returned (owned by the
1534 ** caller). Each row of pStmt is converted to an Object and appended
1535 ** to the array. If the result set has no rows AND pTgt is NULL then
1536 ** NULL is returned.
1537 */
1538 cson_value * json_stmt_to_array_of_obj(Stmt *pStmt,
1539 cson_value * pTgt){
1540 cson_value * v = pTgt;
1541 cson_array * a = NULL;
1542 char const * warnMsg = NULL;
1543 if(v && !cson_value_is_array(v)){
1544 return NULL;
1545 }
1546 while( (SQLITE_ROW==db_step(pStmt)) ){
1547 cson_value * row = NULL;
1548 if(!a){
1549 if(!v){
1550 v = cson_value_new_array();
1551 }
1552 a = cson_value_get_array(v);
1553 assert(NULL!=a);
1554 }
1555 row = cson_sqlite3_row_to_object(pStmt->pStmt);
1556 if(!row && !warnMsg){
1557 warnMsg = "Could not convert at least one result row to JSON.";
1558 continue;
1559 }
1560 if( 0 != cson_array_append(a, row) ){
1561 cson_value_free(row);
1562 assert( 0 && "Alloc error.");
1563 if(pTgt != v) {
1564 cson_value_free(v);
1565 }
1566 return NULL;
1567 }
1568 }
1569 if(warnMsg){
1570 json_warn( FSL_JSON_W_ROW_TO_JSON_FAILED, warnMsg );
1571 }
1572 return v;
1573
+120 -1
--- src/json_tag.c
+++ src/json_tag.c
@@ -186,11 +186,130 @@
186186
** Impl of /json/tag/find.
187187
*/
188188
static cson_value * json_tag_find(){
189189
cson_value * payV = NULL;
190190
cson_object * pay = NULL;
191
- g.json.resultCode = FSL_JSON_E_NYI;
191
+ cson_value * listV = NULL;
192
+ cson_array * list = NULL;
193
+ char const * zName = NULL;
194
+ char const * zType = NULL;
195
+ char fRaw = 0;
196
+ Stmt q = empty_Stmt;
197
+ int limit = 0;
198
+ int tagid = 0;
199
+
200
+ if( !g.perm.Read ){
201
+ json_set_err(FSL_JSON_E_DENIED,
202
+ "Requires 'o' permissions.");
203
+ return NULL;
204
+ }
205
+ zName = json_find_option_cstr("name",NULL,NULL);
206
+ if(!zName || !*zName){
207
+ if(!fossil_is_json()){
208
+ zName = json_command_arg(3);
209
+ }
210
+ if(!zName || !*zName){
211
+ json_set_err(FSL_JSON_E_MISSING_ARGS,
212
+ "'name' parameter is missing.");
213
+ return NULL;
214
+ }
215
+ }
216
+ zType = json_find_option_cstr("type",NULL,"t");
217
+ if(!zType || !*zType){
218
+ zType = "*";
219
+ }
220
+
221
+ tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='sym-%q'",
222
+ zName);
223
+#if 0
224
+ /* It is arguable to return an error in this case. We could
225
+ alternatively simply return an empty set.
226
+ */
227
+ if( tagid<=0 ){
228
+ json_set_err(FSL_JSON_E_RESOURCE_NOT_FOUND,
229
+ "Could not find tag ID for tag '%s'.", zName);
230
+ return NULL;
231
+ }
232
+#endif
233
+
234
+ limit = json_find_option_int("limit",NULL,"n",0);
235
+ fRaw = json_find_option_bool("raw",NULL,NULL,0);
236
+ payV = cson_value_new_object();
237
+ pay = cson_value_get_object(payV);
238
+ cson_object_set(pay, "name", json_new_string(zName));
239
+ cson_object_set(pay, "raw", cson_value_new_bool(fRaw));
240
+ cson_object_set(pay, "type", json_new_string(zType));
241
+ cson_object_set(pay, "limit", json_new_int(limit));
242
+
243
+#if 1
244
+ if( tagid<=0 ){
245
+ cson_object_set(pay,"artifacts", cson_value_null());
246
+ return payV;
247
+ }
248
+#endif
249
+
250
+ if( fRaw ){
251
+ db_prepare(&q,
252
+ "SELECT blob.uuid FROM tagxref, blob"
253
+ " WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q)"
254
+ " AND tagxref.tagtype>0"
255
+ " AND blob.rid=tagxref.rid"
256
+ "%s LIMIT %d",
257
+ zName,
258
+ (limit>0)?"":"--", limit
259
+ );
260
+ printf("SQL=%s\n", blob_buffer(&q.sql));
261
+ while( db_step(&q)==SQLITE_ROW ){
262
+ if(!listV){
263
+ listV = cson_value_new_array();
264
+ list = cson_value_get_array(listV);
265
+ }
266
+ cson_array_append(list, cson_sqlite3_column_to_value(q.pStmt,0));
267
+ }
268
+ db_finalize(&q);
269
+ }else{
270
+ char const * zSqlBase = /*modified from timeline_query_for_tty()*/
271
+ " SELECT"
272
+#if 0
273
+ " blob.rid AS rid,"
274
+#endif
275
+ " uuid AS uuid,"
276
+ " cast(strftime('%s',event.mtime) as int) AS mtime,"
277
+ " coalesce(ecomment,comment) AS comment,"
278
+ " coalesce(euser,user) AS user,"
279
+ " CASE event.type"
280
+ " WHEN 'ci' THEN 'checkin'"
281
+ " WHEN 'w' THEN 'wiki'"
282
+ " WHEN 'e' THEN 'event'"
283
+ " WHEN 't' THEN 'ticket'"
284
+ " ELSE 'WTF?'"
285
+ " END"
286
+ " AS eventType"
287
+ " FROM event, blob"
288
+ " WHERE blob.rid=event.objid"
289
+ ;
290
+ /* FIXME: re-add tags. */
291
+ db_prepare(&q,
292
+ "%s"
293
+ " AND event.type GLOB '%q'"
294
+ " AND blob.rid IN ("
295
+ " SELECT rid FROM tagxref"
296
+ " WHERE tagtype>0 AND tagid=%d"
297
+ " )"
298
+ " ORDER BY event.mtime DESC"
299
+ "%s LIMIT %d",
300
+ zSqlBase, zType, tagid,
301
+ (limit>0)?"":"--", limit
302
+ );
303
+ listV = json_stmt_to_array_of_obj(&q, NULL);
304
+ db_finalize(&q);
305
+ }
306
+
307
+ if(!listV) {
308
+ listV = cson_value_null();
309
+ }
310
+ cson_object_set(pay, "artifacts", listV);
192311
return payV;
193312
}
194313
195314
196315
/*
197316
--- src/json_tag.c
+++ src/json_tag.c
@@ -186,11 +186,130 @@
186 ** Impl of /json/tag/find.
187 */
188 static cson_value * json_tag_find(){
189 cson_value * payV = NULL;
190 cson_object * pay = NULL;
191 g.json.resultCode = FSL_JSON_E_NYI;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
192 return payV;
193 }
194
195
196 /*
197
--- src/json_tag.c
+++ src/json_tag.c
@@ -186,11 +186,130 @@
186 ** Impl of /json/tag/find.
187 */
188 static cson_value * json_tag_find(){
189 cson_value * payV = NULL;
190 cson_object * pay = NULL;
191 cson_value * listV = NULL;
192 cson_array * list = NULL;
193 char const * zName = NULL;
194 char const * zType = NULL;
195 char fRaw = 0;
196 Stmt q = empty_Stmt;
197 int limit = 0;
198 int tagid = 0;
199
200 if( !g.perm.Read ){
201 json_set_err(FSL_JSON_E_DENIED,
202 "Requires 'o' permissions.");
203 return NULL;
204 }
205 zName = json_find_option_cstr("name",NULL,NULL);
206 if(!zName || !*zName){
207 if(!fossil_is_json()){
208 zName = json_command_arg(3);
209 }
210 if(!zName || !*zName){
211 json_set_err(FSL_JSON_E_MISSING_ARGS,
212 "'name' parameter is missing.");
213 return NULL;
214 }
215 }
216 zType = json_find_option_cstr("type",NULL,"t");
217 if(!zType || !*zType){
218 zType = "*";
219 }
220
221 tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='sym-%q'",
222 zName);
223 #if 0
224 /* It is arguable to return an error in this case. We could
225 alternatively simply return an empty set.
226 */
227 if( tagid<=0 ){
228 json_set_err(FSL_JSON_E_RESOURCE_NOT_FOUND,
229 "Could not find tag ID for tag '%s'.", zName);
230 return NULL;
231 }
232 #endif
233
234 limit = json_find_option_int("limit",NULL,"n",0);
235 fRaw = json_find_option_bool("raw",NULL,NULL,0);
236 payV = cson_value_new_object();
237 pay = cson_value_get_object(payV);
238 cson_object_set(pay, "name", json_new_string(zName));
239 cson_object_set(pay, "raw", cson_value_new_bool(fRaw));
240 cson_object_set(pay, "type", json_new_string(zType));
241 cson_object_set(pay, "limit", json_new_int(limit));
242
243 #if 1
244 if( tagid<=0 ){
245 cson_object_set(pay,"artifacts", cson_value_null());
246 return payV;
247 }
248 #endif
249
250 if( fRaw ){
251 db_prepare(&q,
252 "SELECT blob.uuid FROM tagxref, blob"
253 " WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q)"
254 " AND tagxref.tagtype>0"
255 " AND blob.rid=tagxref.rid"
256 "%s LIMIT %d",
257 zName,
258 (limit>0)?"":"--", limit
259 );
260 printf("SQL=%s\n", blob_buffer(&q.sql));
261 while( db_step(&q)==SQLITE_ROW ){
262 if(!listV){
263 listV = cson_value_new_array();
264 list = cson_value_get_array(listV);
265 }
266 cson_array_append(list, cson_sqlite3_column_to_value(q.pStmt,0));
267 }
268 db_finalize(&q);
269 }else{
270 char const * zSqlBase = /*modified from timeline_query_for_tty()*/
271 " SELECT"
272 #if 0
273 " blob.rid AS rid,"
274 #endif
275 " uuid AS uuid,"
276 " cast(strftime('%s',event.mtime) as int) AS mtime,"
277 " coalesce(ecomment,comment) AS comment,"
278 " coalesce(euser,user) AS user,"
279 " CASE event.type"
280 " WHEN 'ci' THEN 'checkin'"
281 " WHEN 'w' THEN 'wiki'"
282 " WHEN 'e' THEN 'event'"
283 " WHEN 't' THEN 'ticket'"
284 " ELSE 'WTF?'"
285 " END"
286 " AS eventType"
287 " FROM event, blob"
288 " WHERE blob.rid=event.objid"
289 ;
290 /* FIXME: re-add tags. */
291 db_prepare(&q,
292 "%s"
293 " AND event.type GLOB '%q'"
294 " AND blob.rid IN ("
295 " SELECT rid FROM tagxref"
296 " WHERE tagtype>0 AND tagid=%d"
297 " )"
298 " ORDER BY event.mtime DESC"
299 "%s LIMIT %d",
300 zSqlBase, zType, tagid,
301 (limit>0)?"":"--", limit
302 );
303 listV = json_stmt_to_array_of_obj(&q, NULL);
304 db_finalize(&q);
305 }
306
307 if(!listV) {
308 listV = cson_value_null();
309 }
310 cson_object_set(pay, "artifacts", listV);
311 return payV;
312 }
313
314
315 /*
316

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button