08cc33e57afb8e6cadcf195e9c9178c84b871720
hiram
  Fri Apr 19 14:59:12 2019 -0700
correctly wiggle data output adding split table testing refs #18869

diff --git src/hg/hubApi/getData.c src/hg/hubApi/getData.c
index a6dd07f..10e9cec 100644
--- src/hg/hubApi/getData.c
+++ src/hg/hubApi/getData.c
@@ -1,59 +1,63 @@
 /* manage endpoint /getData/ functions */
 
 #include "dataApi.h"
 
 static unsigned wigTableDataOutput(struct jsonWrite *jw, char *database,
 	char *table, char *chrom, int start, int end, unsigned itemsDone)
 /* output wiggle data from the given table and specified chrom:start-end */
 {
 struct wiggleDataStream *wds = wiggleDataStreamNew();
 wds->setMaxOutput(wds, maxItemsOutput);
 wds->setChromConstraint(wds, chrom);
 wds->setPositionConstraint(wds, start, end);
 int operations = wigFetchAscii;
-long long valuesMatched = wds->getData(wds, database, table, operations);
-jsonWriteNumber(jw, "valuesMatched", valuesMatched);
+(void) wds->getData(wds, database, table, operations);
 struct wigAsciiData *el;
-jsonWriteListStart(jw, chrom);
 unsigned itemCount = 0;
 for (el = wds->ascii; (itemCount + itemsDone) < maxItemsOutput && el; el = el->next)
     {
-    int s = el->data->chromStart;
-    int e = s + el->span;
-    double val = el->data->value;
+    unsigned span = el->span;
+    unsigned count = el->count;
+    unsigned i = 0;
+    struct asciiDatum *data = el->data;
+    for ( ; ((itemCount + itemsDone) < maxItemsOutput) && i < count; ++i,++data)
+	{
+	int s = data->chromStart;
+	int e = s + span;
+	double val = data->value;
 	if (jsonOutputArrays)
 	    {
 	    jsonWriteListStart(jw, NULL);
 	    jsonWriteNumber(jw, NULL, (long long)s);
 	    jsonWriteNumber(jw, NULL, (long long)e);
 	    jsonWriteDouble(jw, NULL, val);
 	    jsonWriteListEnd(jw);
 	    }
 	else
 	    {
 	    jsonWriteObjectStart(jw, NULL);
 	    jsonWriteNumber(jw, "start", (long long)s);
 	    jsonWriteNumber(jw, "end", (long long)e);
 	    jsonWriteDouble(jw, "value", val);
 	    jsonWriteObjectEnd(jw);
 	    }
 	++itemCount;
 	}
-jsonWriteListEnd(jw);
-return itemCount;
     }
+return itemCount;
+}	/* static unsigned wigTableDataOutput(struct jsonWrite *jw, ...) */
 
 static void jsonDatumOut(struct jsonWrite *jw, char *name, char *val,
     int jsonType)
 /* output a json item, determine type, appropriate output, name can be NULL */
 {
 if (JSON_DOUBLE == jsonType)
     jsonWriteDouble(jw, name, sqlDouble(val));
 else if (JSON_NUMBER == jsonType)
     jsonWriteNumber(jw, name, sqlLongLong(val));
 else
     jsonWriteString(jw, name, val);
 }
 
 static void wigColumnTypes(struct jsonWrite *jw)
 /* output column headers for a wiggle data output schema */
@@ -216,50 +220,54 @@
      * determine if split, and then will go through each chrom
      */
     sqlDyStringPrintf(query, "select * from %s", splitSqlTable);
     }
 else if (0 == (start + end))	/* have chrom, no start,end == full chr */
     {
     if (! sqlColumnExists(conn, splitSqlTable, chromName))
 	apiErrAbort(err400, err400Msg, "track '%s' is not a position track, request track without chrom specification, genome: '%s'", track, db);
 
     jsonWriteString(jw, "chrom", chrom);
     struct chromInfo *ci = hGetChromInfo(db, chrom);
     jsonWriteNumber(jw, "start", (long long)0);
     jsonWriteNumber(jw, "end", (long long)ci->size);
     if (startsWith("wig", tdb->type))
 	{
+	jsonWriteListStart(jw, NULL);
 	if (jsonOutputArrays || debug)
 	    wigColumnTypes(jw);
         wigTableDataOutput(jw, db, splitSqlTable, chrom, 0, ci->size, 0);
+	jsonWriteListEnd(jw);
         return;	/* DONE */
 	}
     else
 	{
 	sqlDyStringPrintf(query, "select * from %s where %s='%s'", splitSqlTable, chromName, chrom);
 	}
     }
 else	/* fully specified chrom:start-end */
     {
     jsonWriteString(jw, "chrom", chrom);
     jsonWriteNumber(jw, "start", (long long)start);
     jsonWriteNumber(jw, "end", (long long)end);
     if (startsWith("wig", tdb->type))
 	{
+	jsonWriteListStart(jw, NULL);
 	if (jsonOutputArrays || debug)
 	    wigColumnTypes(jw);
         wigTableDataOutput(jw, db, splitSqlTable, chrom, start, end, 0);
+	jsonWriteListEnd(jw);
         return;	/* DONE */
 	}
     else
 	{
 	sqlDyStringPrintf(query, "select * from %s where ", splitSqlTable);
         hAddBinToQuery(start, end, query);
 	sqlDyStringPrintf(query, "%s='%s' AND %s > %u AND %s < %u", chromName, chrom, endName, start, startName, end);
 	}
     }
 
 if (debug)
     jsonWriteString(jw, "select", query->string);
 
 /* continuing, not a wiggle output */
 char **columnNames = NULL;
@@ -294,68 +302,70 @@
 
 	    /* perhaps move the comment pointer forward */
 	    if (columnEl)
 		{
 		if (asColumnCount == columnCount)
 		    columnEl = columnEl->next;
 		else if (! ((0 == i) && (hti && hti->hasBin)))
 		    columnEl = columnEl->next;
 		}
 	    jsonWriteObjectEnd(jw);
 	}
 	jsonWriteListEnd(jw);
 	}
     }
 
-/* data output list starting */
-jsonWriteListStart(jw, track);
-
 unsigned itemsDone = 0;
 
 /* empty chrom, needs to run through all chrom names */
 if (isEmpty(chrom))
     {
+    jsonWriteObjectStart(jw, track);	/* begin track data output */
     char fullTableName[256];
     struct chromInfo *ciList = createChromInfoList(NULL, db);
     slSort(ciList, chromInfoCmp);
-    struct chromInfo *el = ciList;
-    for ( ; itemsDone < maxItemsOutput && el != NULL; el = el->next )
+    struct chromInfo *ci = ciList;
+    for ( ; itemsDone < maxItemsOutput && ci != NULL; ci = ci->next )
 	{
+	jsonWriteListStart(jw, ci->chrom);	/* starting a chrom output */
 	freeDyString(&query);
 	query = dyStringNew(64);
 	if (hti && hti->isSplit) /* when split, make up split chr name */
 	    {
-	    safef(fullTableName, sizeof(fullTableName), "%s_%s", el->chrom, hti->rootName);
+	    safef(fullTableName, sizeof(fullTableName), "%s_%s", ci->chrom, hti->rootName);
 	    sqlDyStringPrintf(query, "select * from %s", fullTableName);
 	    }
 	else
 	    sqlDyStringPrintf(query, "select * from %s", splitSqlTable);
 	if (startsWith("wig", tdb->type))
             itemsDone += wigTableDataOutput(jw, db, splitSqlTable, chrom,
 		start, end, itemsDone);
 	else
 	    itemsDone += sqlQueryJsonOutput(conn, jw, query->string,
 		columnCount, columnNames, jsonTypes, itemsDone);
+	jsonWriteListEnd(jw);	/* chrom data output list end */
 	}
+    jsonWriteObjectEnd(jw);	/* end track data output */
     }
 else
-    {
+    {	/* a single chrom has been requested, run it */
+    jsonWriteListStart(jw, track);	/* data output list starting */
     itemsDone += sqlQueryJsonOutput(conn, jw, query->string, columnCount,
 	columnNames, jsonTypes, itemsDone);
+    jsonWriteListEnd(jw);	/* data output list end */
     }
 freeDyString(&query);
-jsonWriteListEnd(jw);	/* data output list end */
 }	/*  static void tableDataOutput(char *db, struct trackDb *tdb, ... ) */
 
 static boolean typedBig9Plus(struct trackDb *tdb)
 /* check if track type is 'bed 9+ ...' to determine itemRgb for big* types */
 {
 if (isNotEmpty(tdb->type) && (allowedBigBedType(tdb->type)))
     {
     char *words[8];
     int wordCount;
     wordCount = chopLine(cloneString(tdb->type), words);
     if ( (wordCount > 1) && startsWith("bigBed", words[0]))
 	{
 	if (isAllDigits(words[1]))
 	   if (8 < sqlUnsigned(words[1]))
 		return TRUE;