d86d0030a9eb8ebce064d942456b42e6f82874cf
angie
  Tue Sep 25 14:11:18 2018 -0700
In altOrPatch mode, if prefix matching yields no results, then try matching any part of sequence names.  Treat '.' as a single-char wildcard so 'KI270857.1' can match chr17_KI270857v1_alt. refs #18854

diff --git src/hg/hgSuggest/hgSuggest.c src/hg/hgSuggest/hgSuggest.c
index 2f740f4..ceff555 100644
--- src/hg/hgSuggest/hgSuggest.c
+++ src/hg/hgSuggest/hgSuggest.c
@@ -83,73 +83,91 @@
         dyStringPrintf(str, "%s{\"value\": \"%s (%s)\", "
                        "\"id\": \"%s:%d-%s\", "
                        "\"geneSymbol\": \"%s\", "
                        "\"internalId\": \"%s\"}",
                        count == 1 ? "" : ",\n", row[0], jsonStringEscape(description),
                        row[1], atoi(row[2])+1, row[3],
                        jsonStringEscape(row[0]),
                        jsonStringEscape(row[4]));
         }
     }
 hFreeConn(&conn);
 dyStringPrintf(str, "\n]\n");
 puts(dyStringContents(str));
 }
 
-struct slName *queryQNames(struct sqlConnection *conn, char *table, char *prefix)
-/* If table exists, return qNames in table that match prefix, otherwise NULL. */
+struct slName *queryQNames(struct sqlConnection *conn, char *table, char *term, boolean prefixOnly)
+/* If table exists, return qNames in table that match term, otherwise NULL. */
 {
 struct slName *names = NULL;
 if (sqlTableExists(conn, table))
     {
+    // If there is a ".", make it into a single-character wildcard so that "GL383518.1"
+    // can match "chr1_GL383518v1_alt".
+    char termCpy[strlen(term)+1];
+    safecpy(termCpy, sizeof termCpy, term);
+    subChar(termCpy, '.', '?');
+    // Escape '_' because that is an important character in alt/fix sequence names, and support
+    // wildcards:
+    char *escapedTerm = sqlLikeFromWild(termCpy);
     char query[2048];
-    sqlSafef(query, sizeof query, "select distinct(qName) from %s where qName like '%s%%' "
-             "order by qName", table, sqlLikeFromWild(prefix));
+    sqlSafef(query, sizeof query, "select distinct(qName) from %s where qName like '%s%s%%' "
+             "order by qName",
+             table, (prefixOnly ? "" : "%"), escapedTerm);
     names = sqlQuickList(conn, query);
     }
 return names;
 }
 
 void writeAltFixMatches(struct jsonWrite *jw, struct slName *matches, char *category)
 /* Append JSON objects containing alt or fix patch sequence names & optional category. */
 {
 struct slName *match;
 for (match = matches; match != NULL; match = match->next)
     {
     if (strchr(match->name, '_'))
         {
         jsonWriteObjectStart(jw, NULL);
         jsonWriteString(jw, "value", match->name);
         if (isNotEmpty(category))
             jsonWriteString(jw, "category", category);
         jsonWriteObjectEnd(jw);
         }
     }
 }
 
-void suggestAltOrPatch(char *database, char *prefix)
+void suggestAltOrPatch(char *database, char *term)
 /* Print out a Javascript list of objects describing alternate haplotype or fix patch sequences
- * from database that match prefix. */
+ * from database that match term. */
 {
 struct jsonWrite *jw = jsonWriteNew();
 jsonWriteListStart(jw, NULL);
 struct sqlConnection *conn = hAllocConn(database);
-struct slName *fixMatches = queryQNames(conn, "fixSeqLiftOverPsl", prefix);
-struct slName *altMatches = queryQNames(conn, "altSeqLiftOverPsl", prefix);
+// First, search for prefix matches
+struct slName *fixMatches = queryQNames(conn, "fixSeqLiftOverPsl", term, TRUE);
+struct slName *altMatches = queryQNames(conn, "altSeqLiftOverPsl", term, TRUE);
 // Add category labels only if we get both types of matches.
 writeAltFixMatches(jw, fixMatches, altMatches ? "Fix Patches" : "");
 writeAltFixMatches(jw, altMatches, fixMatches ? "Alt Patches" : "");
+// If there are no prefix matches, look for partial matches
+if (fixMatches == NULL && altMatches == NULL)
+    {
+    fixMatches = queryQNames(conn, "fixSeqLiftOverPsl", term, FALSE);
+    altMatches = queryQNames(conn, "altSeqLiftOverPsl", term, FALSE);
+    writeAltFixMatches(jw, fixMatches, altMatches ? "Fix Patches" : "");
+    writeAltFixMatches(jw, altMatches, fixMatches ? "Alt Patches" : "");
+    }
 hFreeConn(&conn);
 jsonWriteListEnd(jw);
 puts(jw->dy->string);
 jsonWriteFree(&jw);
 }
 
 char *checkParams(char *database, char *prefix, char *type)
 /* If we don't have valid CGI parameters, quit with a Bad Request HTTP response. */
 {
 pushWarnHandler(htmlVaBadRequestAbort);
 pushAbortHandler(htmlVaBadRequestAbort);
 if(prefix == NULL || database == NULL)
     errAbort("%s", "Missing prefix and/or db CGI parameter");
 if (! hDbIsActive(database))
     errAbort("'%s' is not a valid, active database", htmlEncode(database));