dbd8fef5786457ba53375f006c4eaedf3d256110
hiram
  Fri Apr 5 11:46:55 2019 -0700
now output correct string or number json types refs #18869

diff --git src/hg/hubApi/getData.c src/hg/hubApi/getData.c
index 8353baf..6deddbb 100644
--- src/hg/hubApi/getData.c
+++ src/hg/hubApi/getData.c
@@ -18,30 +18,42 @@
 for (el = wds->ascii; itemCount < maxItemsOutput && el; el = el->next)
     {
     jsonWriteObjectStart(jw, NULL);
     int s = el->data->chromStart;
     int e = s + el->span;
     double val = el->data->value;
     jsonWriteNumber(jw, "start", (long long)s);
     jsonWriteNumber(jw, "end", (long long)e);
     jsonWriteDouble(jw, "value", val);
     jsonWriteObjectEnd(jw);
     ++itemCount;
     }
 jsonWriteListEnd(jw);
 }
 
+static void jsonDatumOut(struct jsonWrite *jw, char *name, char *val,
+    int jsonType)
+/* output a json item, determine type, appropriate output */
+{
+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 tableDataOutput(char *db, struct trackDb *tdb,
     struct sqlConnection *conn, struct jsonWrite *jw, char *table,
     char *chrom, unsigned start, unsigned end)
 /* output the table data from the specified query string */
 {
 char query[4096];
 /* no chrom specified, return entire table */
 if (isEmpty(chrom))
     sqlSafef(query, sizeof(query), "select * from %s", table);
 else if (0 == (start + end))	/* have chrom, no start,end == full chr */
     {
     /* need to extend the chrom column check to allow tName also */
     if (! sqlColumnExists(conn, table, "chrom"))
 	apiErrAbort("track '%s' is not a position track, request track without chrom specification, genome: '%s'", table, db);
     jsonWriteString(jw, "chrom", chrom);
@@ -68,104 +80,93 @@
         wigTableDataOutput(jw, db, table, chrom, start, end);
         return;	/* DONE */
 	}
     else
 	{
 	if (useTxStartEnd)
 	    sqlSafef(query, sizeof(query), "select * from %s where chrom='%s' AND txEnd > %u AND txStart < %u", table, chrom, start, end);
 	else
 	    sqlSafef(query, sizeof(query), "select * from %s where chrom='%s' AND chromEnd > %u AND chromStart < %u", table, chrom, start, end);
 	}
     }
 
 /* continuing, not a wiggle output */
 char **columnNames = NULL;
 char **columnTypes = NULL;
-int columnCount = tableColumns(conn, jw, table, &columnNames, &columnTypes);
+int *jsonTypes = NULL;
+int columnCount = tableColumns(conn, jw, table, &columnNames, &columnTypes, &jsonTypes);
+if (debug)
+    {
+    jsonWriteObjectStart(jw, "columnTypes");
+    int i = 0;
+    for (i = 0; i < columnCount; ++i)
+	{
+	char bothTypes[1024];
+	safef(bothTypes, sizeof(bothTypes), "%s - %s", columnTypes[i], jsonTypeStrings[jsonTypes[i]]);
+	jsonWriteString(jw, columnNames[i], bothTypes);
+//	jsonWriteString(jw, columnNames[i], columnTypes[i]);
+	}
+    jsonWriteObjectEnd(jw);
+    }
 jsonWriteListStart(jw, table);
 struct sqlResult *sr = sqlGetResult(conn, query);
 char **row = NULL;
 unsigned itemCount = 0;
 while (itemCount < maxItemsOutput && (row = sqlNextRow(sr)) != NULL)
     {
     jsonWriteObjectStart(jw, NULL);
     int i = 0;
     for (i = 0; i < columnCount; ++i)
-	jsonWriteString(jw, columnNames[i], row[i]);
+	{
+	jsonDatumOut(jw, columnNames[i], row[i], jsonTypes[i]);
+	}
     jsonWriteObjectEnd(jw);
     ++itemCount;
     }
 sqlFreeResult(&sr);
 jsonWriteListEnd(jw);
 }
 
-/* from hgTables.h */
-struct sqlFieldType
-/* List field names and types */
-    {
-    struct sqlFieldType *next;
-    char *name;         /* Name of field. */
-    char *type;         /* Type of field (MySQL notion) */
-    }; 
-
-/* from hgTables.c */
-static struct sqlFieldType *sqlFieldTypeNew(char *name, char *type)
-/* Create a new sqlFieldType */
-{
-struct sqlFieldType *ft;
-AllocVar(ft);
-ft->name = cloneString(name);
-ft->type = cloneString(type);
-return ft;
-}
-
-/* from hgTables.c */
-static struct sqlFieldType *sqlFieldTypesFromAs(struct asObject *as)
-/* Convert asObject to list of sqlFieldTypes */
-{
-struct sqlFieldType *ft, *list = NULL;
-struct asColumn *col;
-for (col = as->columnList; col != NULL; col = col->next)
-    {
-    struct dyString *type = asColumnToSqlType(col);
-    ft = sqlFieldTypeNew(col->name, type->string);
-    slAddHead(&list, ft);
-    dyStringFree(&type);
-    }
-slReverse(&list);
-return list;
-}
-
 static void bedDataOutput(struct jsonWrite *jw, struct bbiFile *bbi,
     char *chrom, unsigned start, unsigned end, struct sqlFieldType *fiList)
 /* output bed data for one chrom in the given bbi file */
 {
+int *jsonTypes = NULL;
+int columnCount = slCount(fiList);
+AllocArray(jsonTypes, columnCount);
+int i = 0;
+struct sqlFieldType *fi;
+for ( fi = fiList; fi; fi = fi->next)
+    {
+    jsonTypes[i++] = autoSqlToJsonType(fi->type);
+    }
 struct lm *bbLm = lmInit(0);
 struct bigBedInterval *iv, *ivList = NULL;
 ivList = bigBedIntervalQuery(bbi,chrom, start, end, 0, bbLm);
 char *row[bbi->fieldCount];
 unsigned itemCount = 0;
 for (iv = ivList; itemCount < maxItemsOutput && iv; iv = iv->next)
     {
     char startBuf[16], endBuf[16];
     bigBedIntervalToRow(iv, chrom, startBuf, endBuf, row, bbi->fieldCount);
     jsonWriteObjectStart(jw, NULL);
     int i;
     struct sqlFieldType *fi = fiList;
     for (i = 0; i < bbi->fieldCount; ++i)
         {
-        jsonWriteString(jw, fi->name, row[i]);
+        jsonDatumOut(jw, fi->name, row[i], jsonTypes[i]);
+//        jsonWriteString(jw, fi->name, row[i]);
         fi = fi->next;
         }
     jsonWriteObjectEnd(jw);
     ++itemCount;
     }
 lmCleanup(&bbLm);
 }
 
 static void wigDataOutput(struct jsonWrite *jw, struct bbiFile *bwf,
     char *chrom, unsigned start, unsigned end)
 /* output wig data for one chrom in the given bwf file */
 {
 struct lm *lm = lmInit(0);
 struct bbiInterval *iv, *ivList = bigWigIntervalQuery(bwf, chrom, start, end, lm);
 if (NULL == ivList)
@@ -196,30 +197,45 @@
 struct bbiChromInfo *chromList = NULL;
 // struct bbiSummaryElement sum = bbiTotalSummary(bwf);
 if (isEmpty(chrom))
     {
     chromList = bbiChromList(bwf);
     struct bbiChromInfo *bci;
     for (bci = chromList; bci; bci = bci->next)
 	{
 	wigDataOutput(jw, bwf, bci->name, 0, bci->size);
 	}
     }
     else
 	wigDataOutput(jw, bwf, chrom, start, end);
 }
 
+static void bigColumnTypes(struct jsonWrite *jw, struct sqlFieldType *fiList)
+/* show the column types from a big file autoSql definitions */
+{
+jsonWriteObjectStart(jw, "columnTypes");
+struct sqlFieldType *fi = fiList;
+for ( ; fi; fi = fi->next)
+    {
+    char bothTypes[1024];
+    int jsonType = autoSqlToJsonType(fi->type);
+    safef(bothTypes, sizeof(bothTypes), "%s - %s", fi->type, jsonTypeStrings[jsonType]);
+    jsonWriteString(jw, fi->name, bothTypes);
+    }
+jsonWriteObjectEnd(jw);
+}
+
 static void getHubTrackData(char *hubUrl)
 /* return data from a hub track, optionally just one chrom data,
  *  optionally just one section of that chrom data
  */
 {
 char *genome = cgiOptionalString("genome");
 char *track = cgiOptionalString("track");
 char *chrom = cgiOptionalString("chrom");
 char *start = cgiOptionalString("start");
 char *end = cgiOptionalString("end");
 
 if (isEmpty(genome))
     apiErrAbort("missing genome=<name> for endpoint '/getData/track'  given hubUrl='%s'", hubUrl);
 if (isEmpty(track))
     apiErrAbort("missing track=<name> for endpoint '/getData/track'  given hubUrl='%s'", hubUrl);
@@ -274,30 +290,33 @@
 if ( ! (isEmpty(start) || isEmpty(end)) )
     {
     uStart = sqlUnsigned(start);
     uEnd = sqlUnsigned(end);
     jsonWriteNumber(jw, "start", uStart);
     jsonWriteNumber(jw, "end", uEnd);
     }
 
 jsonWriteString(jw, "bigDataUrl", bigDataUrl);
 jsonWriteString(jw, "trackType", thisTrack->type);
 
 if (startsWith("bigBed", thisTrack->type))
     {
     struct asObject *as = bigBedAsOrDefault(bbi);
     struct sqlFieldType *fiList = sqlFieldTypesFromAs(as);
+    if (debug)
+        bigColumnTypes(jw, fiList);
+
     jsonWriteListStart(jw, track);
     if (isEmpty(chrom))
 	{
 	struct bbiChromInfo *bci;
 	for (bci = chromList; bci; bci = bci->next)
 	    {
 	    bedDataOutput(jw, bbi, bci->name, 0, bci->size, fiList);
 	    }
 	}
     else
 	bedDataOutput(jw, bbi, chrom, uStart, uEnd, fiList);
     jsonWriteListEnd(jw);
     }
 else if (startsWith("bigWig", thisTrack->type))
     {
@@ -414,30 +433,32 @@
 	}
      jsonWriteString(jw, "bigDataUrl", bigDataUrl);
     }
 
 /* when start, end given, show them */
 if ( uEnd > uStart )
     {
     jsonWriteNumber(jw, "start", uStart);
     jsonWriteNumber(jw, "end", uEnd);
     }
 
 if (startsWith("bigBed", thisTrack->type))
     {
     struct asObject *as = bigBedAsOrDefault(bbi);
     struct sqlFieldType *fiList = sqlFieldTypesFromAs(as);
+    if (debug)
+        bigColumnTypes(jw, fiList);
     jsonWriteListStart(jw, track);
     if (isEmpty(chrom))
 	{
 	struct bbiChromInfo *bci;
 	for (bci = chromList; bci; bci = bci->next)
 	    {
 	    bedDataOutput(jw, bbi, bci->name, 0, bci->size, fiList);
 	    }
 	}
     else
 	bedDataOutput(jw, bbi, chrom, uStart, uEnd, fiList);
     jsonWriteListEnd(jw);
     }
 else if (startsWith("bigWig", thisTrack->type))
     {