fd6b31a3f5776f7f3fa7ddc617a559de6ab3ff5c
chmalee
  Fri May 2 16:01:20 2025 -0700
Add bigGenePred to 'zoomToExon' and 'zoomToCodon' feature, refs #33963

diff --git src/hg/hgApi/hgApi.c src/hg/hgApi/hgApi.c
index 59d489437a9..b2e74711e2a 100644
--- src/hg/hgApi/hgApi.c
+++ src/hg/hgApi/hgApi.c
@@ -27,45 +27,48 @@
 
 codonToPos: returns genomic position for given exon; parameters: exon, table and name (which is gene name).
 */
 
 #include "common.h"
 #include "hdb.h"
 #include "mdb.h"
 #include "cheapcgi.h"
 #include "htmshell.h"
 #include "hPrint.h"
 #include "dystring.h"
 #include "hui.h"
 #include "search.h"
 #include "cv.h"
 #include "api.h"
+#include "chromAlias.h"
+#include "bigBed.h"
+#include "trackHub.h"
 
 int main(int argc, char *argv[])
 {
 long enteredMainTime = clock1000();
 struct dyString *output = dyStringNew(10000);
 
 setUdcCacheDir();
 cgiSpoof(&argc, argv);
 pushWarnHandler(htmlVaBadRequestAbort);
 pushAbortHandler(htmlVaBadRequestAbort);
 
 char *database = cgiString("db");
 char *cmd = cgiString("cmd");
 char *jsonp = cgiOptionalString("jsonp");
-if (!hDbExists(database))
+if (!trackHubDatabase(database) && !hDbExists(database))
     errAbort("Invalid database '%s'", database);
 
 if (!strcmp(cmd, "defaultPos"))
     {
     dyStringPrintf(output, "{\"pos\": \"%s\"}", hDefaultPos(database));
     }
 else if (!strcmp(cmd, "metaDb"))
     {
     // Return list of values for given metaDb var
     // e.g. http://genome.ucsc.edu/hgApi?db=hg18&cmd=metaDb&var=cell
 
     struct sqlConnection *conn = hAllocConn(database);
     boolean metaDbExists = sqlTableExists(conn, "metaDb");
     if (metaDbExists)
         {
@@ -180,48 +183,67 @@
             }
         else
             dyStringPrintf(output,"Track %s not found",trackName);
         }
     else
         dyStringAppend(output,"No track variable found");
     }
 else if (sameString(cmd, "codonToPos") || sameString(cmd, "exonToPos"))
     {
     char query[256];
     struct sqlResult *sr;
     char **row;
     struct genePred *gp;
     char *name = cgiString("name");
     char *table = cgiString("table");
+    char *chrom = cgiString("chrom");
     int num = cgiInt("num");
-    struct sqlConnection *conn = hAllocConn(database);
-    sqlSafef(query, sizeof(query), "select name, chrom, strand, txStart, txEnd, cdsStart, cdsEnd, exonCount, exonStarts, exonEnds from %s where name = '%s'", table, name);
-    sr = sqlGetResult(conn, query);
-    if ((row = sqlNextRow(sr)) != NULL)
+    struct sqlConnection *conn;
+    if (!trackHubDatabase(database))
+        conn = hAllocConn(database);
+    struct trackDb *tdb = tdbForTrack(database, table, NULL);
+    if (sameString(tdb->type, "genePred"))
         {
+        sqlSafef(query, sizeof(query), "select name, chrom, strand, txStart, txEnd, cdsStart, cdsEnd, exonCount, exonStarts, exonEnds from %s where name = '%s' and chrom='%s'", table, name, chrom);
+        sr = sqlGetResult(conn, query);
+        row = sqlNextRow(sr);
         gp = genePredLoad(row);
-        boolean found;
-        int start, end;
+        sqlFreeResult(&sr);
+        }
+    else if (sameString(tdb->type, "bigGenePred") ||
+            startsWith("bigGenePred", tdb->type)) // makes knownGene work
+        {
+        // TODO: what bigBed types can we even support? bigBed12 at a minimum for the blocks?
+        // bigPsl should work maybe?
+        // for now just support genePred and bigGenePred
+        char *fileName = bbiNameFromSettingOrTable(tdb, conn, tdb->table);
+        struct bbiFile *bbi = bigBedFileOpenAlias(fileName, chromAliasFindAliases);
+        int fieldIx;
+        struct bptFile *bpt = bigBedOpenExtraIndex(bbi, "name", &fieldIx);
+        struct lm *lm = lmInit(0);
+        struct bigBedInterval *bbList = bigBedNameQuery(bbi, bpt, fieldIx, name, lm);
+        if (bbList)
+            gp = (struct genePred *)genePredFromBigGenePred(chrom, bbList);
+        }
+    if (!gp)
+        dyStringPrintf(output, "{\"error\": \"Couldn't find item: %s\"}", name);
+    boolean found; int start, end;
     if (sameString(cmd, "codonToPos"))
         found = codonToPos(gp, num, &start, &end);
     else
         found = exonToPos(gp, num, &start, &end);
     if (found)
         dyStringPrintf(output, "{\"pos\": \"%s:%d-%d\"}", gp->chrom, start + 1, end);
     else
         dyStringPrintf(output, "{\"error\": \"%d is an invalid %s for this gene\"}", num, sameString(cmd, "codonToPos") ? "codon" : "exon");
-        }
-    else
-        dyStringPrintf(output, "{\"error\": \"Couldn't find item: %s\"}", name);
-    sqlFreeResult(&sr);
     hFreeConn(&conn);
     }
 else
     {
     warn("unknown cmd: %s",cmd);
     errAbort("Unsupported 'cmd' parameter");
     }
 
 apiOut(dyStringContents(output), jsonp);
 cgiExitTime("hgApi", enteredMainTime);
 return 0;
 }