f31b0c7755da1ffe944a89e1d0a572eafa135ea7
angie
Mon Jan 26 15:48:43 2015 -0800
Add yet another special case for all_* tables.
diff --git src/hg/hgAi/hgAi.c src/hg/hgAi/hgAi.c
index d15ddaf..9f9b78a 100644
--- src/hg/hgAi/hgAi.c
+++ src/hg/hgAi/hgAi.c
@@ -1,346 +1,351 @@
/* hgAi - bootstrapper / back end for the Annotation Integrator user interface
* This CGI has three modes of operation:
* - HTML output for minimal main page with a
container to be filled in by javascript
* (default, in the absence of special CGI params)
* - JSON responses to ajax requests from javascript (using hg/lib/cartJson.c)
* (if CGI param CARTJSON_COMMAND exists)
* - text output for annoGrator queries on track data
* (if CGI param DO_QUERY exists)
* The UI view top level is in ../js/react/hgAi/hgAi.jsx
* The UI model top level is in ../js/model/hgAi/hgAiModel.js
*/
#include "common.h"
#include "cart.h"
#include "cartJson.h"
#include "cartTrackDb.h"
#include "cheapcgi.h"
#include "hAnno.h"
#include "hCommon.h"
#include "hdb.h"
#include "hgColors.h"
#include "hui.h"
#include "jsonParse.h"
#include "textOut.h"
#include "trackHub.h"
#include "web.h"
#include "annoFormatTab.h"
#include "annoGratorQuery.h"
/* Global Variables */
struct cart *cart = NULL; /* CGI and other variables */
#define QUERY_SPEC "hgai_querySpec"
#define DO_QUERY "hgai_doQuery"
//#*** duplicated from hgVai... put in some anno*.h?
#define NO_MAXROWS 0
static void writeDbMetadata(struct cartJson *cj, struct hash *paramHash)
/* Send all the info that we'll need for working with a specific assembly db. */
{
cartJsonGetGroupsTracksTables(cj, paramHash);
//#*** TODO: move jsonStringEscape inside jsonWriteString
char *encoded = jsonStringEscape(cartOptionalString(cart, QUERY_SPEC));
jsonWriteString(cj->jw, QUERY_SPEC, encoded);
}
static void changeDb(struct cartJson *cj, struct hash *paramHash)
/* The user has changed db; send groups, tracks, tables etc. for the new db. */
{
cartJsonChangeDb(cj, paramHash);
writeDbMetadata(cj, paramHash);
}
static void changeOrg(struct cartJson *cj, struct hash *paramHash)
/* The user has changed org/genome; send groups, tracks, tables etc. for the new default db. */
{
cartJsonChangeOrg(cj, paramHash);
writeDbMetadata(cj, paramHash);
}
static void changeClade(struct cartJson *cj, struct hash *paramHash)
/* The user has changed clade; send groups, tracks, tables etc. for the new default db. */
{
cartJsonChangeClade(cj, paramHash);
writeDbMetadata(cj, paramHash);
}
static void makeTrackLabel(struct trackDb *tdb, char *table, char *label, size_t labelSize)
/* Write tdb->shortLabel into label if table is the same as tdb->track; otherwise, write shortLabel
* followed by table name in parens. */
{
if (sameString(table, tdb->track))
safecpy(label, labelSize, tdb->shortLabel);
else
safef(label, labelSize, "%s (%s)", tdb->shortLabel, table);
}
static void getFields(struct cartJson *cj, struct hash *paramHash)
/* Print out the fields of the tables in comma-sep tables param. */
{
char *tableStr = cartJsonRequiredParam(paramHash, "tables", cj->jw, "getFields");
if (! tableStr)
return;
char *db = cartString(cart, "db");
struct slName *table, *tables = slNameListFromComma(tableStr);
jsonWriteObjectStart(cj->jw, "tableFields");
struct trackDb *fullTrackList = NULL;
struct grp *fullGroupList = NULL;
cartTrackDbInit(cj->cart, &fullTrackList, &fullGroupList, /* useAccessControl= */TRUE);
for (table = tables; table != NULL; table = table->next)
{
- struct trackDb *tdb = tdbForTrack(NULL, table->name, &fullTrackList);
+ char *tableName = table->name;
+ if (startsWith("all_", tableName))
+ tableName += strlen("all_");
+ struct trackDb *tdb = tdbForTrack(NULL, tableName, &fullTrackList);
if (tdb)
{
struct asObject *asObj = hAnnoGetAutoSqlForTdb(db, hDefaultChrom(db), tdb);
if (asObj)
{
jsonWriteObjectStart(cj->jw, table->name);
char label[strlen(tdb->shortLabel) + strlen(table->name) + PATH_LEN];
makeTrackLabel(tdb, table->name, label, sizeof(label));
jsonWriteString(cj->jw, "label", label);
jsonWriteListStart(cj->jw, "fields");
struct asColumn *col;
for (col = asObj->columnList; col != NULL; col = col->next)
jsonWriteString(cj->jw, NULL, col->name);
jsonWriteListEnd(cj->jw);
jsonWriteObjectEnd(cj->jw);
}
}
+ else
+ warn("No tdb for %s", table->name);
}
jsonWriteObjectEnd(cj->jw);
slFreeList(&tables);
}
void doCartJson()
/* Perform UI commands to update the cart and/or retrieve cart vars & metadata. */
{
struct cartJson *cj = cartJsonNew(cart);
cartJsonRegisterHandler(cj, "changeDb", changeDb);
cartJsonRegisterHandler(cj, "changeOrg", changeOrg);
cartJsonRegisterHandler(cj, "changeClade", changeClade);
cartJsonRegisterHandler(cj, "getFields", getFields);
cartJsonExecute(cj);
}
static struct pipeline *configTextOut(struct jsonElement *queryObj, int *pSavedStdout)
// Set up a textOut pipeline according to output file options in queryObj.
{
char *fileName = "";
char *compressType = textOutCompressNone;
struct jsonElement *outFileOptions = jsonFindNamedField(queryObj, QUERY_SPEC, "outFileOptions");
if (outFileOptions)
{
boolean doFile = jsonOptionalBooleanField(outFileOptions, "doFile", FALSE);
if (doFile)
{
fileName = jsonOptionalStringField(outFileOptions, "fileName", "hgAiResults");
boolean doGzip = jsonOptionalBooleanField(outFileOptions, "doGzip", FALSE);
if (doGzip)
compressType = textOutCompressGzip;
}
}
return textOutInit(fileName, compressType, pSavedStdout);
}
static struct annoFormatter *makeTabFormatter(struct jsonElement *queryObj)
// Create and configure an annoFormatter subclass as specified by queryObj.
{
struct annoFormatter *tabOut = annoFormatTabNew("stdout");
// Look for fields that have been deselected by the user
struct jsonElement *outFileOptions = jsonFindNamedField(queryObj, QUERY_SPEC, "outFileOptions");
if (outFileOptions)
{
struct jsonElement *tableFieldsObj = jsonFindNamedField(outFileOptions, "outFileOptions",
"tableFields");
if (tableFieldsObj)
{
struct hash *tableFields = jsonObjectVal(tableFieldsObj, "tableFields");
// Iterate over names which are tables which had better end up being annoStreamer names...
//#*** Hmmm, annoStreamer uses complete file path for big and we don't have that info
//#*** here. Better find a way to pass in names to streamers for consistency!
struct hashEl *hel;
struct hashCookie cookie = hashFirst(tableFields);
while ((hel = hashNext(&cookie)) != NULL)
{
char *sourceName = hel->name;
struct jsonElement *tableObj = hel->val;
struct hash *fieldVals = jsonObjectVal(tableObj, sourceName);
// Now iterate over field/column names to see which ones are explicitly deselected:
struct hashEl *innerHel;
struct hashCookie innerCookie = hashFirst(fieldVals);
while ((innerHel = hashNext(&innerCookie)) != NULL)
{
char *colName = innerHel->name;
struct jsonElement *enabledEl = innerHel->val;
boolean enabled = jsonBooleanVal(enabledEl, colName);
if (! enabled)
annoFormatTabSetColumnVis(tabOut, sourceName, colName, enabled);
}
}
}
}
return tabOut;
}
void doQuery()
/* Execute a query that has been built up by the UI. */
{
// Make sure we have either genome-wide search or a valid position
char *db = cartString(cart, "db");
char *chrom = NULL;
uint start = 0, end = 0;
char *regionType = cartUsualString(cart, "hgai_range", "position");
if (sameString(regionType, "position"))
{
char *position = cartUsualString(cart, "position", hDefaultPos(db));
if (! parsePosition(position, &chrom, &start, &end))
errAbort("doQuery: Expected position to be chrom:start-end but got '%s'", position);
}
struct annoAssembly *assembly = hAnnoGetAssembly(db);
// Decode and parse CGI-encoded querySpec.
char *querySpec = cartString(cart, QUERY_SPEC);
int len = strlen(querySpec);
char querySpecDecoded[len+1];
cgiDecodeFull(querySpec, querySpecDecoded, len);
struct jsonElement *queryObj = jsonParse(querySpecDecoded);
// Set up output.
int savedStdout = -1;
struct pipeline *textOutPipe = configTextOut(queryObj, &savedStdout);
webStartText();
// Build annoGrator query.
struct slRef *dataSources = jsonListVal(jsonFindNamedField(queryObj, "queryObj", "dataSources"),
"dataSources");
struct grp *fullGroupList = NULL;
struct trackDb *fullTrackList = NULL;
cartTrackDbInit(cart, &fullTrackList, &fullGroupList, TRUE);
struct annoStreamer *primary = NULL;
struct annoGrator *gratorList = NULL;
struct slRef *dsRef;
int i;
for (i = 0, dsRef = dataSources; dsRef != NULL; i++, dsRef = dsRef->next)
{
struct jsonElement *dsObj = dsRef->val;
char *table = jsonStringField(dsObj, "table");
char *track = jsonStringField(dsObj, "track");
struct trackDb *tdb = tdbForTrack(db, table, &fullTrackList);
if (!tdb)
tdb = tdbForTrack(db, track, &fullTrackList);
if (!tdb)
errAbort("doQuery: no tdb for track %s, table %s", track, table);
if (i == 0)
{
primary = hAnnoStreamerFromTrackDb(assembly, table, tdb, chrom, NO_MAXROWS);
annoStreamerSetName(primary, table);
}
else
{
struct annoGrator *grator = hAnnoGratorFromTrackDb(assembly, table, tdb, chrom,
NO_MAXROWS, NULL, agoNoConstraint);
if (grator)
{
annoStreamerSetName((struct annoStreamer *)grator, table);
slAddHead(&gratorList, grator);
}
else
errAbort("doQuery: no grator for track %s, table %s", track, table);
}
}
slReverse(&gratorList);
// Make an annoFormatter to print output.
// For now, tab-separated output is it.
struct annoFormatter *formatter = makeTabFormatter(queryObj);
// Set up and execute query.
struct annoGratorQuery *query = annoGratorQueryNew(assembly, primary, gratorList, formatter);
if (chrom != NULL)
annoGratorQuerySetRegion(query, chrom, start, end);
annoGratorQueryExecute(query);
annoGratorQueryFree(&query);
textOutClose(&textOutPipe, &savedStdout);
}
void doMainPage()
/* Send HTML with javascript to bootstrap the user interface. */
{
char *db = cartUsualString(cart, "db", hDefaultDb());
webStartWrapperDetailedNoArgs(cart, trackHubSkipHubName(db),
"", "Annotation Integrator",
TRUE, FALSE, TRUE, TRUE);
// Ideally these would go in the
puts("");
puts("");
puts("
Loading...
");
// Set a global JS variable hgsid.
// Plain old "var ..." doesn't work (other scripts can't see it), it has to belong to window.
printf("\n", cartSessionVarName(), cartSessionId(cart));
// We need a package manager and require-handling system... bower and browserify?
puts("");
puts("");
puts("");
puts("");
puts("");
puts("");
puts("");
puts("");
puts("");
puts("");
puts("");
puts("");
puts("");
puts("");
puts("");
puts("");
puts("");
puts("");
// Invisible form for submitting a query
printf("\n");
// Invisible form for jumping to another CGI
printf("\n");
webEnd();
}
void doMiddle(struct cart *theCart)
/* Depending on invocation, either perform a query and print out results,
* serve up JSON for the UI, or display the main page. */
{
cart = theCart;
if (cgiOptionalString(CARTJSON_COMMAND))
doCartJson();
else if (cgiOptionalString(DO_QUERY))
doQuery();
else
doMainPage();
}
int main(int argc, char *argv[])
/* Process CGI / command line. */
{
/* Null terminated list of CGI Variables we don't want to save
* permanently. */
char *excludeVars[] = {DO_QUERY, CARTJSON_COMMAND, NULL,};
struct hash *oldVars = NULL;
cgiSpoof(&argc, argv);
setUdcCacheDir();
cartEmptyShellNoContent(doMiddle, hUserCookie(), excludeVars, oldVars);
return 0;
}