536e32480cf89093ba8b82ff4e73b0a9ca6ac389 chmalee Fri Oct 28 13:29:33 2022 -0700 Fix multiTerm searches and plain chromosome searches, refs #29693 diff --git src/hg/lib/hgFind.c src/hg/lib/hgFind.c index 8b75f1d..1c0ff15 100644 --- src/hg/lib/hgFind.c +++ src/hg/lib/hgFind.c @@ -3288,32 +3288,32 @@ tsrList = trixSearch(category->trix, keyCount, keyWords, tsmExpand); struct errCatch *errCatch = errCatchNew(); if (errCatchStart(errCatch)) initSnippetIndex(category->trix); errCatchEnd(errCatch); // silently return if there was a problem opening the snippet index if (errCatch->gotError || errCatch->gotWarning) return FALSE; errCatchFree(&errCatch); } struct trixSearchResult *tsr = NULL; int len = 0; struct hgPosTable *table = NULL; AllocVar(table); table->searchTime = -1; -table->name = category->name; -table->description = category->description; +table->name = cloneString(category->name); +table->description = cloneString(category->description); for (tsr = tsrList; tsr != NULL; tsr = tsr->next) { if (startsWith(category->name,"publicHubs")) { // Check that this public hubs result is for our current database char *itemId[5]; int numItems = chopString(cloneString(tsr->itemId), ":", itemId, ArraySize(itemId)); if (numItems <= 2 || isEmpty(itemId[2]) || !sameString(itemId[2], database)) continue; } struct errCatch *errCatch = errCatchNew(); if (errCatchStart(errCatch)) { addSnippetForResult(tsr, category->trix); } @@ -3346,76 +3346,90 @@ break; } if (table->posList != NULL) { slReverse(&table->posList); if (measureTiming) table->searchTime = clock1000() - startTime; slAddHead(&hgp->tableList, table); ret = TRUE; } return ret; } static boolean userDefinedSearch(char *db, char *term, int limitResults, struct cart *cart, - struct hgPositions *hgp, struct searchCategory *categories, boolean measureTiming) + struct hgPositions *hgp, struct searchCategory *categories, boolean multiTerm, boolean measureTiming) /* If a search type(s) is specified in the cart, perform that search. * If the search is successful, fill in hgp and return TRUE. */ { boolean foundIt = FALSE; struct hash *foundSpecHash = hashNew(0); struct hgFindSpec *shortList = NULL, *longList = NULL; struct trackDb *hubCategoryList = NULL; // get all the lists of what to query: if (!trackHubDatabase(db)) { if (categories) myLoadFindSpecs(db, categories, &shortList, &longList); else hgFindSpecGetAllSpecs(db, &shortList, &longList); } // lastly search any included track hubs, or in the case of an assembly hub, any of the tracks hubCategoryList = hubCategoriesToTdbList(categories); struct hgFindSpec *hfs; for (hfs = shortList; hfs != NULL; hfs = hfs->next) { - boolean foundSpec = hgFindUsingSpec(cart, db, hfs, term, limitResults, hgp, FALSE, 0, 0, FALSE, measureTiming); + boolean foundSpec = hgFindUsingSpec(cart, db, hfs, term, limitResults, hgp, FALSE, 0, 0, multiTerm, measureTiming); if (foundSpec) hashAdd(foundSpecHash, hfs->searchTable, hfs->searchTable); foundIt |= foundSpec; + + // for multiTerm searches (like '15q11;15q13'), each individual component + // must resolve to a single position, so break once we find the first match + if (multiTerm && foundSpec) + break; } +if (multiTerm && !foundIt) + { for (hfs = longList; hfs != NULL; hfs = hfs->next) { if (hashFindVal(foundSpecHash, hfs->searchTable) != NULL) continue; - foundIt |= hgFindUsingSpec(cart, db, hfs, term, limitResults, hgp, FALSE, 0, 0, FALSE, measureTiming); + foundIt |= hgFindUsingSpec(cart, db, hfs, term, limitResults, hgp, FALSE, 0, 0, multiTerm, measureTiming); } // lastly search any included track hubs, or in the case of an assembly hub, any of the tracks if (hubCategoryList) foundIt |= findBigBedPosInTdbList(cart, db, hubCategoryList, term, hgp, NULL, measureTiming); + } + +// multiTerm searches must resolve to a single range on a chromosome, so don't +// do these non positional searches if a multiTerm was requested +if (!multiTerm) + { getLabelsForHubs(); struct searchCategory *category; for (category = categories; category != NULL; category = category->next) { if (startsWith("trackDb", category->id) || sameString(category->id, "helpDocs") || sameString(category->id, "publicHubs")) { foundIt |= doTrixQuery(category, term, hgp, db, measureTiming); } } + } return foundIt; } static boolean singleSearch(char *db, char *term, int limitResults, struct cart *cart, struct hgPositions *hgp, boolean measureTiming) /* If a search type is specified in the CGI line (not cart), perform that search. * If the search is successful, fill in hgp as a single-pos result and return TRUE. */ { char *search = cgiOptionalString("singleSearch"); if (search == NULL) return FALSE; cartRemove(cart, "singleSearch"); boolean foundIt = FALSE; @@ -3645,32 +3659,52 @@ term = trimSpaces(term); if(isEmpty(term)) return hgp; hgp->query = cloneString(term); hgp->database = db; if (extraCgi == NULL) extraCgi = ""; hgp->extraCgi = cloneString(extraCgi); if (singleSearch(db, term, limitResults, cart, hgp, measureTiming)) return hgp; if (categories != NULL) { - if (!matchesHgvs(cart, db, term, hgp, measureTiming)) - userDefinedSearch(db, term, limitResults, cart, hgp, categories, measureTiming); + char *originalTerm = term; + if (hgOfficialChromName(db, term) != NULL) // this mangles the term + { + char *chrom; + int start, end; + + hgParseChromRange(db, term, &chrom, &start, &end); + if (relativeFlag) + { + int chromSize = end; + end = start + relEnd; + start = start + relStart; + if (end > chromSize) + end = chromSize; + if (start < 0) + start = 0; + } + singlePos(hgp, "Chromosome Range", NULL, "chromInfo", originalTerm, + "", chrom, start, end); + } + else if (!matchesHgvs(cart, db, term, hgp, measureTiming)) + userDefinedSearch(db, term, limitResults, cart, hgp, categories, multiTerm, measureTiming); slReverse(&hgp->tableList); if (multiTerm) collapseSamePos(hgp); fixSinglePos(hgp); if (cart && hgp->singlePos && isNotEmpty(hgp->singlePos->highlight)) cartSetString(cart, "addHighlight", hgp->singlePos->highlight); if (hgp->posCount > 0) return hgp; else // if categories was passed in we should explicitly return no results // if there weren't any return NULL; } /* Allow any search term to end with a :Start-End range -- also support stuff