2770a53d1e8e0e5773020965d19c2499439481ca chmalee Tue Feb 7 13:33:08 2023 -0800 Make hubApi return data from multiple tracks at once. Get trackDb tableBrowser setting working correctly in the api diff --git src/hg/hubApi/getData.c src/hg/hubApi/getData.c index 9a7541f..14fce17 100644 --- src/hg/hubApi/getData.c +++ src/hg/hubApi/getData.c @@ -545,58 +545,72 @@ } bbiFileClose(&bbi); apiFinishOutput(0, NULL, jw); } /* static void getHubTrackData(char *hubUrl) */ static void getTrackData() /* return data from a track, optionally just one chrom data, * optionally just one section of that chrom data */ { char *db = cgiOptionalString("genome"); char *chrom = cgiOptionalString("chrom"); char *start = cgiOptionalString("start"); char *end = cgiOptionalString("end"); /* 'track' name in trackDb often refers to a SQL 'table' */ -char *track = cgiOptionalString("track"); -char *sqlTable = cloneString(track); /* might be something else */ +char *trackArg = cgiOptionalString("track"); +char *sqlTable = cloneString(trackArg); /* might be something else */ /* depends upon 'table' setting in track db, or split table business */ unsigned chromSize = 0; /* maybe set later */ unsigned uStart = 0; unsigned uEnd = chromSize; /* maybe set later */ if ( ! (isEmpty(start) || isEmpty(end)) ) { uStart = sqlUnsigned(start); uEnd = sqlUnsigned(end); if (uEnd < uStart) apiErrAbort(err400, err400Msg, "given start coordinate %u is greater than given end coordinate", uStart, uEnd); } if (isEmpty(db)) apiErrAbort(err400, err400Msg, "missing URL variable genome= name for endpoint '/getData/track"); -if (isEmpty(track)) +if (isEmpty(trackArg)) apiErrAbort(err400, err400Msg, "missing URL variable track= name for endpoint '/getData/track"); /* database existence has already been checked before now, might * have disappeared in the mean time (well, not really . . .) */ struct sqlConnection *conn = hAllocConnMaybe(db); if (NULL == conn) apiErrAbort(err400, err400Msg, "can not find genome 'genome=%s' for endpoint '/getData/track", db); -struct trackDb *thisTrack = hTrackDbForTrack(db, track); +struct jsonWrite *jw = apiStartOutput(); + +// load the tracks +struct trackDb *tdbList = NULL; +cartTrackDbInitForApi(NULL, db, &tdbList, NULL, FALSE); + +// allow optional comma sep list of tracks +char *tracks[100]; +int numTracks = chopByChar(trackArg, ',', tracks, sizeof(tracks)); +int i = 0; +for (i = 0; i < numTracks; i++) + { + char *track = cloneString(tracks[i]); + char *sqlTable = cloneString(track); + struct trackDb *thisTrack = tdbForTrack(db, track, &tdbList); if (NULL == thisTrack) { if (! sqlTableExists(conn, track)) apiErrAbort(err400, err400Msg, "can not find track=%s name for endpoint '/getData/track", track); } if (thisTrack && ! isSupportedType(thisTrack->type)) apiErrAbort(err415, err415Msg, "track type '%s' for track=%s not supported at this time", thisTrack->type, track); if (trackHasNoData(thisTrack)) apiErrAbort(err400, err400Msg, "container track '%s' does not contain data, use the children of this container", track); /* might be a big* track with no table */ char *bigDataUrl = NULL; boolean tableTrack = TRUE; @@ -606,31 +620,31 @@ /* might have a specific table defined instead of the track name */ char *tableName = trackDbSetting(thisTrack, "table"); if (isNotEmpty(tableName)) { freeMem(sqlTable); sqlTable = cloneString(tableName); } } else { freeMem(sqlTable); sqlTable = cloneString(track); } -if (protectedTrack(thisTrack, sqlTable)) + if (protectedTrack(db, thisTrack, sqlTable) && !(chrom && start && end)) apiErrAbort(err403, err403Msg, "this data request: 'db=%s;track=%s' is protected data, see also: https://genome.ucsc.edu/FAQ/FAQdownloads.html#download40", db, track); struct hTableInfo *hti = hFindTableInfoWithConn(conn, NULL, sqlTable); char *splitSqlTable = NULL; if (hti && hti->isSplit) { if (isNotEmpty(chrom)) { char fullTableName[256]; safef(fullTableName, sizeof(fullTableName), "%s_%s", chrom, hti->rootName); splitSqlTable = cloneString(fullTableName); } else @@ -638,31 +652,30 @@ char *defaultChrom = hDefaultChrom(db); char fullTableName[256]; safef(fullTableName, sizeof(fullTableName), "%s_%s", defaultChrom, hti->rootName); splitSqlTable = cloneString(fullTableName); } } if (! hTableOrSplitExists(db, sqlTable)) { if (! bigDataUrl) apiErrAbort(err400, err400Msg, "can not find specified 'track=%s' for endpoint: /getData/track?genome=%s;track=%s", track, db, track); else tableTrack = FALSE; } -struct jsonWrite *jw = apiStartOutput(); jsonWriteString(jw, "genome", db); if (tableTrack) { char *dataTime = NULL; if (hti && hti->isSplit) dataTime = sqlTableUpdate(conn, splitSqlTable); else dataTime = sqlTableUpdate(conn, sqlTable); time_t dataTimeStamp = sqlDateToUnixTime(dataTime); replaceChar(dataTime, ' ', 'T'); /* ISO 8601 */ jsonWriteString(jw, "dataTime", dataTime); jsonWriteNumber(jw, "dataTimeStamp", (long long)dataTimeStamp); if (differentStringNullOk(sqlTable,track)) jsonWriteString(jw, "sqlTable", sqlTable); } @@ -746,30 +759,31 @@ itemsReturned += itemsDone; jsonWriteListEnd(jw); } else if (thisTrack && startsWith("bigWig", thisTrack->type)) { if (jsonOutputArrays || debug) wigColumnTypes(jw); jsonWriteObjectStart(jw, track); bigWigData(jw, bbi, chrom, uStart, uEnd); jsonWriteObjectEnd(jw); bbiFileClose(&bbi); } else tableDataOutput(db, thisTrack, conn, jw, track, chrom, uStart, uEnd); + } apiFinishOutput(0, NULL, jw); hFreeConn(&conn); } /* static void getTrackData() */ static void getSequenceData(char *db, char *hubUrl) /* return DNA sequence, given at least a genome=name and chrom=chr, optionally start and end, might be a track hub for UCSC database */ { char *chrom = cgiOptionalString("chrom"); char *start = cgiOptionalString("start"); char *end = cgiOptionalString("end"); long timeStart = clock1000();