4b7050d8e3bce0273a6012e16587db4d8a75e127 braney Wed Aug 29 14:57:27 2018 -0700 add filtering in lists refs #20227 diff --git src/hg/hgTracks/bigBedTrack.c src/hg/hgTracks/bigBedTrack.c index daf5482..c4a434b 100644 --- src/hg/hgTracks/bigBedTrack.c +++ src/hg/hgTracks/bigBedTrack.c @@ -136,62 +136,71 @@ char *setting = trackDbSettingClosestToHome(tdb, filterName); char *value = cartUsualStringClosestToHome(cart, tdb, FALSE, filterName, setting); AllocVar(filter); filter->fieldNum = bbExtraFieldIndex(bbi, field) + 3; filter->comparisonType = COMPARE_REGEXP; regcomp(&filter->regEx, value, REG_NOSUB); return filter; } struct bigBedFilter *bigBedMakeFilterBy(struct cart *cart, struct bbiFile *bbi, struct trackDb *tdb, char *field, struct slName *choices) /* Add a bigBed filter using a trackDb filterBy statement. */ { struct bigBedFilter *filter; +char filterType[4096]; +safef(filterType, sizeof filterType, "%s%s", field, FILTER_TYPE_NAME); +char *setting = cartOrTdbString(cart, tdb, filterType, NULL); AllocVar(filter); filter->fieldNum = bbExtraFieldIndex(bbi, field) + 3; +if (setting && (sameString(setting, FILTERBY_SINGLE_LIST) || sameString(setting, FILTERBY_MULTIPLE_LIST_OR))) + filter->comparisonType = COMPARE_HASH_LIST_OR; +else if (setting && sameString(setting, FILTERBY_MULTIPLE_LIST_AND)) + filter->comparisonType = COMPARE_HASH_LIST_AND; +else filter->comparisonType = COMPARE_HASH; filter->valueHash = newHash(5); +filter->numValuesInHash = slCount(choices); for(; choices; choices = choices->next) hashStore(filter->valueHash, choices->name); return filter; } struct bigBedFilter *bigBedBuildFilters(struct cart *cart, struct bbiFile *bbi, struct trackDb *tdb) /* Build all the numeric and filterBy filters for a bigBed */ { struct bigBedFilter *filters = NULL, *filter; -struct slName *filterSettings = trackDbSettingsWildMatch(tdb, "*Filter"); +struct slName *filterSettings = trackDbSettingsWildMatch(tdb, FILTER_NUMBER_WILDCARD); for(; filterSettings; filterSettings = filterSettings->next) { char *fieldName = cloneString(filterSettings->name); - fieldName[strlen(fieldName) - sizeof "Filter" + 1] = 0; + fieldName[strlen(fieldName) - sizeof FILTER_NUMBER_NAME + 1] = 0; if ((filter = bigBedMakeNumberFilter(cart, bbi, tdb, filterSettings->name, NULL, fieldName)) != NULL) slAddHead(&filters, filter); } -filterSettings = trackDbSettingsWildMatch(tdb, "*FilterText"); +filterSettings = trackDbSettingsWildMatch(tdb, FILTER_TEXT_WILDCARD); for(; filterSettings; filterSettings = filterSettings->next) { char *fieldName = cloneString(filterSettings->name); - fieldName[strlen(fieldName) - sizeof "FilterText" + 1] = 0; + fieldName[strlen(fieldName) - sizeof FILTER_TEXT_NAME + 1] = 0; if ((filter = bigBedMakeFilterText(cart, bbi, tdb, filterSettings->name, fieldName)) != NULL) slAddHead(&filters, filter); } filterBy_t *filterBySet = filterBySetGet(tdb, cart,NULL); filterBy_t *filterBy = filterBySet; for (;filterBy != NULL; filterBy = filterBy->next) { if (filterBy->slChoices && differentString(filterBy->slChoices->name, "All")) { if ((filter = bigBedMakeFilterBy(cart, bbi, tdb, filterBy->column, filterBy->slChoices)) != NULL) slAddHead(&filters, filter); } } @@ -201,30 +210,54 @@ boolean bigBedFilterInterval(char **bedRow, struct bigBedFilter *filters) /* Go through a row and filter based on filters. Return TRUE if all filters are passed. */ { struct bigBedFilter *filter; for(filter = filters; filter; filter = filter->next) { double val = atof(bedRow[filter->fieldNum]); switch(filter->comparisonType) { case COMPARE_REGEXP: if (regexec(&filter->regEx,bedRow[filter->fieldNum], 0, NULL,0 ) != 0) return FALSE; break; + case COMPARE_HASH_LIST_AND: + case COMPARE_HASH_LIST_OR: + { + struct slName *values = commaSepToSlNames(bedRow[filter->fieldNum]); + unsigned found = 0; + for(; values; values = values->next) + { + if (hashLookup(filter->valueHash, values->name)) + { + found++; + if (filter->comparisonType == COMPARE_HASH_LIST_OR) + break; + } + } + if (filter->comparisonType == COMPARE_HASH_LIST_AND) + { + if (found < filter->numValuesInHash) + return FALSE; + } + else if (!found) + return FALSE; + } + break; + case COMPARE_HASH: if (!hashLookup(filter->valueHash, bedRow[filter->fieldNum])) return FALSE; break; case COMPARE_LESS: if (!(val <= filter->value1)) return FALSE; break; case COMPARE_MORE: if (!(val >= filter->value1)) return FALSE; break; case COMPARE_BETWEEN: if (!((val >= filter->value1) && (val <= filter->value2))) return FALSE;