Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | timeline json refactoring, fixed ordering, split tags into an Array. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | json |
Files: | files | file ages | folders |
SHA1: |
d6cbe37b6b63c914167d4461a4032574 |
User & Date: | stephan 2011-09-21 15:22:30.297 |
Context
2011-09-21
| ||
16:31 | started adding infrastructure to report non-fatal warnings. ... (check-in: ad50fe95 user: stephan tags: json) | |
15:22 | timeline json refactoring, fixed ordering, split tags into an Array. ... (check-in: d6cbe37b user: stephan tags: json) | |
14:42 | refactored the prototype timeline code, split off completely from www version (different requirements). ... (check-in: 1ecf3374 user: stephan tags: json) | |
Changes
Changes to src/json.c.
︙ | ︙ | |||
460 461 462 463 464 465 466 467 468 469 470 471 472 473 | */ v = cson_value_new_object(); g.json.param.v = v; g.json.param.o = cson_value_get_object(v); json_gc_add("$PARAMS", v, 1); } /* ** Performs some common initialization of JSON-related state. Must be ** called by the json_page_top() and json_cmd_top() dispatching ** functions to set up the JSON stat used by the dispatched functions. ** ** Implicitly sets up the login information state in CGI mode, but | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 | */ v = cson_value_new_object(); g.json.param.v = v; g.json.param.o = cson_value_get_object(v); json_gc_add("$PARAMS", v, 1); } /* ** Splits zStr (which must not be NULL) into tokens separated by the ** given separator character. If doDeHttp is true then each element ** will be passed through dehttpize(), otherwise they are used ** as-is. Each new element is appended to the given target array ** object, which must not be NULL and ownership of it is not changed ** by this call. ** ** On success, returns the number of items appended to target. On ** error a NEGATIVE number is returned - its absolute value is the ** number of items inserted before the error occurred. There is a ** corner case here if we fail on the 1st element, which will cause 0 ** to be returned, which the client cannot immediately distinguish as ** success or error. ** ** Achtung: leading whitespace of elements is NOT elided. We should ** add an option to do that, but don't have one yet. ** ** Achtung: empty elements will be skipped, meaning consecutive ** empty elements are collapsed. */ int json_string_split( char const * zStr, char separator, char doDeHttp, cson_array * target ){ char const * p = zStr /* current byte */; char const * head = p /* current start-of-token */; unsigned int len = 0 /* current token's length */; int rc = 0 /* return code (number of added elements)*/; assert( zStr && target ); for( ; ; ++p){ if( !*p || (separator == *p) ){ if( len ){/* append head..(head+len) as next array element. */ cson_value * part = NULL; char * zPart = NULL; assert( head != p ); zPart = (char*)malloc(len+1); assert( (zPart != NULL) && "malloc failure" ); memcpy(zPart, head, len); zPart[len] = 0; if(doDeHttp){ dehttpize(zPart); } if( *zPart ){ /* should only fail if someone manages to url-encoded a NUL byte */ part = cson_value_new_string(zPart, strlen(zPart)); if( 0 == cson_array_append( target, part ) ){ ++rc; }else{ cson_value_free(part); rc = rc ? -rc : 0; break; } }else{ assert(0 && "i didn't think this was possible!"); } free(zPart); len = 0; } if( !*p ){ break; } head = p+1; continue; } ++len; } return rc; } /* ** Performs some common initialization of JSON-related state. Must be ** called by the json_page_top() and json_cmd_top() dispatching ** functions to set up the JSON stat used by the dispatched functions. ** ** Implicitly sets up the login information state in CGI mode, but |
︙ | ︙ | |||
517 518 519 520 521 522 523 | that we can simplify command dispatching later on. Note that translating g.argv this way is overkill but allows us to avoid CLI-only special-case handling in other code, e.g. json_command_arg(). */ if( zPath ){/* Either CGI or server mode... */ | | < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < | 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 | that we can simplify command dispatching later on. Note that translating g.argv this way is overkill but allows us to avoid CLI-only special-case handling in other code, e.g. json_command_arg(). */ if( zPath ){/* Either CGI or server mode... */ /* Translate PATH_INFO into JSON array for later convenience. */ json_string_split(zPath, '/', 1, g.json.cmd.a); }else{/* assume CLI mode */ int i; char const * arg; cson_value * part; for(i = 1/*skip argv[0]*/; i < g.argc; ++i ){ arg = g.argv[i]; if( !arg || !*arg ){ |
︙ | ︙ | |||
1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 | } } /* ** Create a temporary table suitable for storing timeline data. */ static void json_timeline_temp_table(void){ static const char zSql[] = @ CREATE TEMP TABLE IF NOT EXISTS json_timeline( @ rid INTEGER PRIMARY KEY, @ uuid TEXT, @ mtime INTEGER, @ timestampString TEXT, @ comment TEXT, | > | 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 | } } /* ** Create a temporary table suitable for storing timeline data. */ static void json_timeline_temp_table(void){ /* Field order MUST match that from json_timeline_query_XXX()!!! */ static const char zSql[] = @ CREATE TEMP TABLE IF NOT EXISTS json_timeline( @ rid INTEGER PRIMARY KEY, @ uuid TEXT, @ mtime INTEGER, @ timestampString TEXT, @ comment TEXT, |
︙ | ︙ | |||
1438 1439 1440 1441 1442 1443 1444 | @ strftime('%%s',event.mtime), @ datetime(event.mtime,'utc'), @ coalesce(ecomment, comment), @ coalesce(euser, user), @ blob.rid IN leaf, @ bgcolor, @ event.type, | | > > > | > > > | < > > > > > > > < < < | | > > > > > > > > | > > > > > > | > > > | | > > > > | | < | > > | | 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 | @ strftime('%%s',event.mtime), @ datetime(event.mtime,'utc'), @ coalesce(ecomment, comment), @ coalesce(euser, user), @ blob.rid IN leaf, @ bgcolor, @ event.type, @ (SELECT group_concat(substr(tagname,5), ',') FROM tag, tagxref @ WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid @ AND tagxref.rid=blob.rid AND tagxref.tagtype>0), @ tagid, @ brief @ FROM event JOIN blob @ WHERE blob.rid=event.objid ; return zBaseSql; } /* ** /json/timeline/ci ** ** Far from complete. */ static cson_value * json_timeline_ci(unsigned int depth){ static const int defaultLimit = 10; cson_value * payV = NULL; cson_object * pay = NULL; cson_value * tmp = NULL; cson_value * listV = NULL; cson_array * list = NULL; int limit = json_getenv_int("n",defaultLimit); int check = 0; Stmt q; Blob sql = empty_blob; if( !g.perm.Read/* && !g.perm.RdTkt && !g.perm.RdWiki*/ ){ g.json.resultCode = FSL_JSON_E_DENIED; return NULL; } payV = cson_value_new_object(); pay = cson_value_get_object(payV); if( limit < 0 ) limit = defaultLimit; json_timeline_temp_table(); blob_append(&sql, "INSERT OR IGNORE INTO json_timeline ", -1); blob_append(&sql, json_timeline_query_ci(), -1 ); blob_append(&sql, "AND event.type IN('ci') ", -1); blob_append(&sql, "ORDER BY mtime DESC ", -1); #define SET(K) if(0!=(check=cson_object_set(pay,K,tmp))){ \ g.json.resultCode = (cson_rc.AllocError==check) \ ? FSL_JSON_E_ALLOC : FSL_JSON_E_UNKNOWN; \ goto error;\ } if(limit){ blob_appendf(&sql,"LIMIT %d ",limit); tmp = cson_value_new_integer(limit); SET("limit"); } db_multi_exec(blob_buffer(&sql)); #if 0 /* only for testing! */ tmp = cson_value_new_string(blob_buffer(&sql),strlen(blob_buffer(&sql))); SET("timelineSql"); #endif blob_reset(&sql); blob_append(&sql, "SELECT rid AS rid," " uuid AS uuid," " mtime AS timestamp," " timestampString AS timestampString," " comment AS comment, " " user AS user," " isLeaf AS isLeaf," /*FIXME: convert to JSON bool */ " bgColor AS bgColor," " eventType AS eventType," " tags AS tags," /*FIXME: split this into a JSON array*/ " tagId AS tagId," " brief AS briefText" " FROM json_timeline" " ORDER BY mtime DESC", -1); db_prepare(&q,blob_buffer(&sql)); tmp = NULL; listV = cson_value_new_array(); list = cson_value_get_array(listV); tmp = listV; SET("timeline"); while( (SQLITE_ROW == db_step(&q) )){ /* convert each row into a JSON object...*/ cson_value * rowV = cson_sqlite3_row_to_object(q.pStmt); cson_object * row = cson_value_get_object(rowV); cson_string const * tagsStr = NULL; if(!row){ /* need a way of warning about this */ continue; } /* Split tags string field into JSON Array... */ cson_array_append(list, rowV); tagsStr = cson_value_get_string(cson_object_get(row,"tags")); if(tagsStr){ cson_value * tagsV = cson_value_new_array(); cson_array * tags = cson_value_get_array(tagsV); if( 0 < json_string_split( cson_string_cstr(tagsStr), ',', 0, tags)){ cson_object_set(row,"tags",tagsV) /*replaces/deletes old tags value, invalidating tagsStr!*/; }else{ cson_value_free(tagsV); } } } db_finalize(&q); #undef SET goto ok; error: cson_value_free(payV); payV = NULL; ok: return payV; |
︙ | ︙ |