05316c62e54dfd3cac589a1ae6001e84c357959b
angie
  Mon Apr 23 08:24:28 2012 -0700
Feature #6152 (Variant Annotation Tool): enhancement to filter logic:filters can be for inclusion or exclusion when the condition is met,
based on the new filter->isExclude.  When a filter is set to rightJoin
and it is for inclusion, annoGratorIntegrate propagates rightJoin
failure if no rows overlap since the condition for inclusion has not
been met.

diff --git src/lib/annoGrator.c src/lib/annoGrator.c
index 7a43c74..7a103b9 100644
--- src/lib/annoGrator.c
+++ src/lib/annoGrator.c
@@ -101,45 +101,52 @@
     }
 }
 
 struct annoRow *annoGratorIntegrate(struct annoGrator *self, struct annoRow *primaryRow,
 				    boolean *retRJFilterFailed)
 /* Given a single row from the primary source, get all overlapping rows from internal
  * source, and produce joined output rows.  If retRJFilterFailed is non-NULL and any
  * overlapping row has a rightJoin filter failure (see annoFilter.h),
  * set retRJFilterFailed and stop. */
 {
 struct annoRow *rowList = NULL;
 agCheckPrimarySorting(self, primaryRow);
 agTrimToStart(self, primaryRow->chrom, primaryRow->start);
 agFetchToEnd(self, primaryRow->chrom, primaryRow->end);
 boolean rjFailHard = (retRJFilterFailed != NULL);
+if (rjFailHard)
+    *retRJFilterFailed = FALSE;
 struct annoRow *qRow;
 for (qRow = self->qHead;  qRow != NULL;  qRow = qRow->next)
     {
     if (qRow->start < primaryRow->end && qRow->end > primaryRow->start &&
 	sameString(qRow->chrom, primaryRow->chrom))
 	{
 	slAddHead(&rowList, annoRowClone(qRow, self->mySource));
 	if (rjFailHard && qRow->rightJoinFail)
 	    {
 	    *retRJFilterFailed = TRUE;
 	    break;
 	    }
 	}
     }
 slReverse(&rowList);
+// If no rows overlapped primary, and there is a right-join, !isExclude (i.e. isInclude) filter,
+// then we need to set retRJFilterFailed because the condition was not met to include
+// the primary item.
+if (rowList == NULL && rjFailHard && self->haveRJIncludeFilter)
+    *retRJFilterFailed = TRUE;
 return rowList;
 }
 
 void annoGratorClose(struct annoStreamer **pSelf)
 /* Free self (including mySource). */
 {
 if (pSelf == NULL)
     return;
 struct annoGrator *self = *(struct annoGrator **)pSelf;
 annoRowFreeList(&(self->qHead), self->mySource);
 self->mySource->close(&(self->mySource));
 freeMem(self->prevPChrom);
 freez(pSelf);
 }
 
@@ -148,48 +155,68 @@
 {
 errAbort("nextRow() called on annoGrator object, but integrate() should be called instead");
 return NULL;
 }
 
 static void agReset(struct annoGrator *self)
 /* Reset all position associated with state */
 {
 freez(&self->prevPChrom);
 self->prevPStart = 0;
 self->eof = FALSE;
 annoRowFreeList(&(self->qHead), (struct annoStreamer *)self);
 self->qTail = NULL;
 }
 
+static boolean filtersHaveRJInclude(struct annoFilter *filters)
+/* Return TRUE if filters have at least one active filter with !isExclude && rightJoin. */
+{
+struct annoFilter *filter;
+for (filter = filters;  filter != NULL;  filter = filter->next)
+    if (filter->op != afNoFilter && !filter->isExclude && filter->rightJoin)
+	return TRUE;
+return FALSE;
+}
+
+static void agSetFilters(struct annoStreamer *vSelf, struct annoFilter *newFilters)
+/* Update filters and re-evaluate self->haveRJIncludeFilter */
+{
+annoStreamerSetFilters(vSelf, newFilters);
+struct annoGrator *self = (struct annoGrator *)vSelf;
+self->haveRJIncludeFilter = filtersHaveRJInclude(vSelf->filters);
+}
+
 void annoGratorSetRegion(struct annoStreamer *vSelf, char *chrom, uint rStart, uint rEnd)
 /* Set genomic region for query, and reset internal state. */
 {
 struct annoGrator *self = (struct annoGrator *)vSelf;
 self->mySource->setRegion((struct annoStreamer *)(self->mySource), chrom, rStart, rEnd);
 agReset(self);
 }
 
 void annoGratorSetQuery(struct annoStreamer *vSelf, struct annoGratorQuery *query)
 /* Set query (to be called only by annoGratorQuery which is created after streamers). */
 {
 struct annoGrator *self = (struct annoGrator *)vSelf;
 self->streamer.query = query;
 self->mySource->setQuery((struct annoStreamer *)(self->mySource), query);
 }
 
 struct annoGrator *annoGratorNew(struct annoStreamer *mySource)
 /* Make a new integrator of columns from mySource with (positions of) rows passed to integrate().
  * mySource becomes property of the new annoGrator. */
 {
 struct annoGrator *self;
 AllocVar(self);
 struct annoStreamer *streamer = &(self->streamer);
 annoStreamerInit(streamer, mySource->getAutoSqlObject(mySource));
 streamer->rowType = mySource->rowType;
+streamer->setFilters = agSetFilters;
 streamer->setRegion = annoGratorSetRegion;
 streamer->setQuery = annoGratorSetQuery;
 streamer->nextRow = noNextRow;
 streamer->close = annoGratorClose;
 self->integrate = annoGratorIntegrate;
 self->mySource = mySource;
+self->haveRJIncludeFilter = filtersHaveRJInclude(streamer->filters);
 return self;
 }